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

时间:2013-04-10 20:50:21

标签: python sqlalchemy

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

User.query.all_active()

all_active()基本上是.filter(User.is_active == True)

能够过滤掉它吗?

User.query.all_active().filter(User.age == 30)

3 个答案:

答案 0 :(得分:38)

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

from sqlalchemy.orm import Query

class MyQuery(Query):

  def all_active(self):
    return self.filter(User.is_active == True)

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

db = SQLAlchemy(session_options={'query_cls': MyQuery})

否则,您可以将参数直接传递给sessionmaker

sessionmaker(bind=engine, query_cls=MyQuery)

截至目前,这个新的查询对象并不那么有趣,因为我们在方法中对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)

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

users = relationship(..., query_class=MyOtherQuery)

答案 1 :(得分:0)

要提供一个自定义方法,该方法将供您从特定父级继承的所有模型使用,首先要提到的是先从Query类继承:

from flask_sqlalchemy import SQLAlchemy, BaseQuery
from sqlalchemy.inspection import inspect

class MyCustomQuery(BaseQuery):
    def all_active(self):
        # get the class
        modelClass = self._mapper_zero().class_
        # get the primary key column
        ins = inspect(modelClass)
        # get a list of passing objects
        passingObjs = []
        for modelObj in self:
            if modelObj.is_active == True:
                # add to passing object list
                passingObjs.append(modelObj.__dict__[ins.primary_key[0].name])
        # change to tuple
        passingObjs = tuple(passingObjs)
        # run a filter on the query object
        return self.filter(ins.primary_key[0].in_(passingObjs))

# add this to the constructor for your DB object
myDB = SQLAlchemy(query_class=MyCustomQuery)

这是用于flask-sqlalchemy的,人们在寻找该答案时仍会到达这里。

答案 2 :(得分:0)

这对我来说很好

class ParentQuery(Query):
    def _get_models(self):     
        if hasattr(query, 'attr'):
            return [query.attr.target_mapper]
        else:
            return self._mapper_zero().class_

    def FilterByCustomer(self):
        model_class = self._get_models()
        return self.filter(model_class.customerId == int(g.customer.get('customerId')))


class AccountWorkflowModel(db.Model):
    query_class = ParentQuery
    .................