sqlAlchemy中的子类通过条件过滤父类

2024-04-19 18:53:03 发布

您现在位置:Python中文网/ 问答频道 /正文

在flask sqlAlchemy中,我有一个类User,其中包括列status,如下所示:

class User(Model):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    status = Column(String(255))
    age = Column(Integer)
    yet_another_property = Column(String(255))

我现在想要一个模型ActiveUser,它表示user表中的所有条目,其中status是{}。在MySQL中,这将是

^{pr2}$

我认为,如果ActiveUserUser的子类,并且通过单表继承(如http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#single-table-inheritance所述),这应该是可行的,如下所示:

class User(Model):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    status = Column(String(255))
    age = Column(Integer)
    yet_another_property = Column(String(255))

    __mapper_args__ = {
        'polymorphic_on':status,
        'polymorphic_identity':'user'
    }

class ActiveUser(User):
    __mapper_args__ = {
        'polymorphic_on':status,
        'polymorphic_identity':'active'
    }

我的第一个问题是:这行得通吗?

事实上,我想让更多的属性更加复杂。所以,实际上,我想要一个类ActiveAdultUser,它表示所有处于active状态且年龄大于或等于18岁的用户。同样,在MySQL中:

SELECT * FROM user 
    WHERE
       user.status = 'active'
    AND
       user.age >= 18;

我的第二个问题是:那么,我该怎么做?

当然我知道,我可以通过将.filter(and_(User.status == 'active', User.age >=18))应用到User上的查询来查询活动成人Users。但是为了干净的代码,我希望在模型级别有这个过滤器。在

我还考虑过重写ActiveUser模型上的查询函数,但这看起来相当粗糙,我不知道在任何情况下是否可以依赖它。在


Tags: 模型trueagestringmodelstatuscolumninteger
2条回答

您可以生成multiple mappers for one class-可在文档的non-traditional mappings部分找到:

However, there is a class of mapper known as the non primary mapper with allows additional mappers to be associated with a class, but with a limited scope of use. This scope typically applies to being able to load rows from an alternate table or selectable unit, but still producing classes which are ultimately persisted using the primary mapping.

因此,您将生成一个非主映射器ActiveUser,而不是子类:

In [9]: ActiveUser = mapper(
   ...:     User,
   ...:     User.__table__.select().
   ...:         where(User.status == "active").
   ...:         alias(),
   ...:     non_primary=True)
   ...:     

In [10]: print(session.query(ActiveUser))
SELECT anon_1.id AS anon_1_id, anon_1.status AS anon_1_status, anon_1.age AS anon_1_age, anon_1.yet_another_property AS anon_1_yet_another_property 
FROM (SELECT user.id AS id, user.status AS status, user.age AS age, user.yet_another_property AS yet_another_property 
FROM user 
WHERE user.status = ?) AS anon_1

另一方面,所有这些可能都是不必要的,您可以在需要时简单地查询活动用户。在

我不认为你可以这样做多态性,因为你不能把一个“大于”的比较。你只能有一个固定的多态\u标识。你不能在两个不同的域上变形。在

对我来说,这是一个你打算“简化”一些已经相对简单的事情。一个带有两个过滤条件的SQL查询并不是一个复杂甚至混乱的语句。在

如果您坚持要这样做,正确的方法是将Query子类化并在其中编写条件。https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery给出了一个如何做到这一点的示例。在

就个人而言,我只会在查询中添加两个过滤器。它远没有子类化在将来的版本中可能会改变的东西那样混乱和脆弱。查询语法可能更持久。在

另一种删除冗余代码的方法是预先编写查询:

q = (User.age >= 18, User.status == "active")
foo = Session.query(User).filter(*q).all()

甚至是

^{pr2}$

如果在代码的适当位置定义q,则可以在整个程序中使用它。这样就不需要在每个查询中重复这两个筛选条件。在

相关问题 更多 >