class Parent(db.Model):
children = db.relationship(Child, backref='parents')
class Child(db.Model):
id = db.Column(db.INTEGER, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey(Parent.id))
is_active = db.Column(db.Boolean, nullable=False, default=True)
假设Parent
和Child
模型具有1:N的关系(显然在上面),我想根据activated
的值仅获得is_active
列。
是否有不需要额外过滤器来仅查询激活的子行的技巧?
例如,
假设Child
表具有以下行:
查询如下:
p = Parent.query.filter(**some_conditions).one()
p.children # Then the second row (id=2, is_active=False) shouldn't be here
最佳
答案 0 :(得分:1)
首先,我不得不对您的模型进行一些修改,以使其成为MCVE。
以下示例与此处的官方文档中的示例非常相似:Specifying Alternate Join Conditions,但关键是:
在构造联接时,relationship()的默认行为是,它使一侧的主键列的值等于另一侧的外键引用列的值。 我们可以使用primaryjoin参数将该条件更改为我们想要的任何方式 ...
因此,按照您的示例,默认情况下,SQLAlchemy将通过遵循Parent.id和Child.parent_id之间的外键路径来加入关系。但是,您可以将此连接条件设置为几乎任何所需的条件。例如:
class Parent(db.Model):
id = db.Column(db.INTEGER, primary_key=True)
children = db.relationship("Child", backref='parents')
active_children = db.relationship("Child",
primaryjoin="and_(Parent.id == Child.parent_id, "
"Child.is_active==True)")
如您所见,我们的primaryjoin
参数现在是and_()
函数调用的字符串表示形式,在该函数调用中,我们要求关系在两个模型之间的外键路径上都进行连接,和来确定Child.is_active
是否为True
。在运行时,SQLAlchemy将评估该函数以发出用于从数据库获取相关行的SQL。
这是我的完整代码和基本测试:
import random
class Parent(db.Model):
id = db.Column(db.INTEGER, primary_key=True)
children = db.relationship("Child", backref='parents')
active_children = db.relationship("Child",
primaryjoin="and_(Parent.id == Child.parent_id, "
"Child.is_active==True)")
class Child(db.Model):
id = db.Column(db.INTEGER, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey(Parent.id))
is_active = db.Column(db.Boolean, nullable=False, default=True)
if __name__ == '__main__':
db.drop_all()
db.create_all()
parent = Parent(id=1)
db.session.add(parent)
for _ in range(10):
child = Child(parent_id=1, is_active=random.choice([True, False]))
db.session.add(child)
db.session.commit()
print(parent.children)
print(parent.active_children)
assert all(c.is_active for c in parent.active_children)
一个警告是,您仍然可以将Child
实例添加到Parent.active_children
的{{1}}关系属性中,会话将对其进行跟踪,并在提交后将其持久化。这仅控制查询时从数据库中提取的结果。