在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
为'active'
的所有条目。在MySQL中使用,这将是
SELECT * FROM user
WHERE
user.status = 'active';
我认为,这应该以某种方式使用ActiveUser
作为User
的子类并通过单表继承(如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;
我的第二个问题是:那么,我该怎样做
当然,我知道,我可以通过将Users
应用于.filter(and_(User.status == 'active', User.age >=18))
上的查询,对有效成年人User
进行查询。但是为了清洁代码,我希望在模型级别上使用此过滤器。
我还想过覆盖ActiveUser
模型上的查询功能,但这看起来相当hacky并且我不知道在任何情况下我是否可以依赖它。
答案 0 :(得分:1)
我不认为你可以用多态来做到这一点,因为你不能把"大于"比较那里。您只能拥有固定的polymorphic_identity。你也不能在两个不同的领域上只变形,只有一个。
对我来说,这是一个你计划简化"一些已经相对简单的东西。具有两个过滤条件的SQL查询几乎不是一个复杂甚至是混乱的语句。
如果您坚持要做到这一点,那么正确的方法是继承Query
并在那里写条件。 https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery给出了如何执行此操作的示例。
就个人而言,我只想在我的查询中添加两个过滤器。它远不如在未来版本中可能会改变的子类化更加混乱和脆弱。查询语法可能更持久。
删除冗余代码的另一种方法是预编写查询:
q = (User.age >= 18, User.status == "active")
foo = Session.query(User).filter(*q).all()
甚至
q = Session.query(User).filter(User.age >= 18, User.status == "active")
foo = q.filter(add your additional filters here).all()
# or if no additional filters needed
foo = q.all()
如果您在代码的合适位置定义q,则可以在整个程序中使用它。这将消除在每个查询中重复这两个过滤条件的需要。
答案 1 :(得分:1)
您可以生成multiple mappers for one class - 位于文档的non-traditional mappings部分:
但是,有一类称为非主要映射器的映射器,允许其他映射器与类关联,但使用范围有限。此范围通常适用于能够从备用表或可选单元加载行,但仍然生成使用主映射最终持久化的类。
因此,您需要生成非主要映射器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
另一方面,所有这些可能都是不必要的,您可以在需要时查询活跃用户。