我在父母与孩子之间有很多对很多的关系。 在我的views.py中,我这样做:
parents = s.query(Parent)
在我的(Jinja2)模板中,我做类似的事情:
for parent in parents:
print("parent {}".format(parent.name))
if parent.children:
for child in parent.children:
print("- has child {}, age {}, {}" \
.format(child.name, child.age, child.hair_color))
这表明所有有或没有孩子的父母都很好。
现在,我想拥有所有父母的相同列表(如上所述),但仅适用于7岁以上且金发的孩子。将会有父母,有孩子或没有孩子。 问题:如何在SQLAlchemy中而不是在普通SQL中做到这一点?
我的模特:
# many-to-many link table: parent - child
parent_mtm_child_table = Table('parent_mtm_child', Base.metadata,
Column('parent_id', Integer, ForeignKey('parent.id')),
Column('child_id', Integer, ForeignKey('child.id'))
)
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
name = Column(String)
# many-to-many relationship with child
children = relationship(
'Child',
secondary=parent_mtm_child_table,
back_populates='parents')
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
hair_color = Column(String)
# many-to-many relationship with parent
parents = relationship(
'Parent',
secondary=parent_mtm_child_table,
back_populates='children')
john = Parent(name='John')
mary = Parent(name='Mary')
gina = Parent(name='Gina')
liam = Child(name='Liam', age=6, hair_color='brown')
emma = Child(name='Emma', age=8, hair_color='blond')
lauren = Child(name='Lauren', age=9, hair_color='blond')
john.children.append(liam)
john.children.append(emma)
mary.children.append(liam)
gina.children.append(lauren)
s.add_all([john, mary, gina, liam, emma, lauren])
s.commit()
下一个查询是错误的,但是给出了我可以检查的生成的SQL:
r = s.query(Parent).outerjoin(Parent.children).filter(Child.age >= 7)
SQL按预期显示了WHERE部分中的额外条件:
sql = 'SELECT parent.id AS parent_id, parent.name AS parent_name \
FROM parent LEFT OUTER JOIN (parent_mtm_child AS parent_mtm_child_1
JOIN child ON child.id = parent_mtm_child_1.child_id)
ON parent.id = parent_mtm_child_1.parent_id \
WHERE child.age >= 7'
将额外条件移到ON-部分后,sql变为:
sql = 'SELECT parent.id AS parent_id, parent.name AS parent_name, child.id AS child_id, child.name AS child_name, child.age AS child_age \
FROM parent \
LEFT OUTER JOIN (parent_mtm_child AS parent_mtm_child_1 \
JOIN child ON ((child.id = parent_mtm_child_1.child_id) AND (child.age >= 7)) ) \
ON parent.id = parent_mtm_child_1.parent_id'
现在执行原始sql:
with engine.connect() as con:
r = con.execute(sql)
for row in r:
print("row = {}".format(row))
结果正确:
row = (1, 'John', 2, 'Emma', 8)
row = (2, 'Mary', None, None, None)
row = (3, 'Gina', 3, 'Lauren', 9)
所以可能一定有可能。
我如何在SQLAlchemy中使用ON-part的额外条件来执行此操作?
我也尝试了contains_eager:
r = s.query(Parent).join(Parent.children).\
filter(Child.age >= 7).\
options(contains_eager(Parent.children)).all()
但是它给出了错误的结果:
parent John
- has child Emma, age 8, blond
- has child Liam, age 6, brown
parent Mary
- has child Liam, age 6, brown
parent Gina
- has child Lauren, age 9, blond
任何帮助表示赞赏。