SQLAlchemy - 您可以向查询对象添加自定义方法吗?

mph*_*uie 24 python sqlalchemy

有没有办法为查询对象创建自定义方法,以便您可以这样做?

User.query.all_active()
Run Code Online (Sandbox Code Playgroud)

all_active()基本上在哪里.filter(User.is_active == True)

能够过滤掉它吗?

User.query.all_active().filter(User.age == 30)
Run Code Online (Sandbox Code Playgroud)

mtt*_*tth 44

您可以继承基Query类以添加自己的方法:

from sqlalchemy.orm import Query

class MyQuery(Query):

  def all_active(self):
    return self.filter(User.is_active == True)
Run Code Online (Sandbox Code Playgroud)

然后,您在创建会话时告诉SQLAlchemy使用此新查询类(此处为docs).从您的代码看起来您​​可能正在使用Flask-SQLAlchemy,因此您可以按如下方式执行:

db = SQLAlchemy(session_options={'query_cls': MyQuery})
Run Code Online (Sandbox Code Playgroud)

否则你会将参数直接传递给sessionmaker:

sessionmaker(bind=engine, query_cls=MyQuery)
Run Code Online (Sandbox Code Playgroud)

截至目前,这个新的查询对象并不那么有趣,因为我们User在方法中对类进行了硬编码,因此它不适用于其他任何东西.更好的实现将使用查询的基础类来确定要应用的过滤器.这有点棘手,但也可以这样做:

class MyOtherQuery(Query):

  def _get_models(self):
    """Returns the query's underlying model classes."""
    if hasattr(query, 'attr'):
      # we are dealing with a subquery
      return [query.attr.target_mapper]
    else:
      return [
        d['expr'].class_
        for d in query.column_descriptions
        if isinstance(d['expr'], Mapper)
      ]

  def all_active(self):
    model_class = self._get_models()[0]
    return self.filter(model_class.is_active == True)
Run Code Online (Sandbox Code Playgroud)

最后,动态关系(如果有的话)不会使用这个新的查询类.为了让那些人也使用它,您可以在创建关系时将其作为参数传递:

users = relationship(..., query_class=MyOtherQuery)
Run Code Online (Sandbox Code Playgroud)

  • 因此,您说一个会话只能使用一个查询类。我们可以做得更好吗?并允许同一会话动态选择查询类?我的意思是不同的表可以具有不同的查询类,但是我可能希望在同一会话中使用它们(例如,在一个事务中使用它们)。 (2认同)