我在sqlalchemy中有3个表,我声明了多对多的关系
父:
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(db.Integer, nullable=False, autoincrement=True, primary_key=True)
name = db.Column(db.String(45))
children = relationship('Child',
secondary = parents_children,
back_populates='parents')
子
class Child(db.Model):
__tablename__ = 'child'
id = db.Column(db.Integer, nullable=False, autoincrement=True, primary_key=True)
name = db.Column(db.String(45), nullable=False)
parents = db.relationship('Parent',
secondary=parents_children,
back_populates='children')
最后是1个关系表:
parents_children= db.Table('parents_children', db.metadata,
db.Column('parent_id', db.Integer, ForeignKey('parent.id')),
db.Column('student_id', db.Integer, ForeignKey('child.id')))
因此,一个孩子可以有一个或多个父母,一个父母可以有一个或多个孩子。
现在让我们说我想带走所有孩子并将它们作为json文件返回。我想带一个child_id,child_name和parent_id,所以我提出了一个问题:
students = db.session.query(Child.id,Child.name,Parent.id).join('parents').all()
我的json就像:
{"children":[
{"name":"child1", "id":"1", "parent_id":"1"},
{"name":"child2", "id":"2", "parent_id":"2"}]}
我的第一个问题是,如果一个孩子有一个以上的父母,我的json文件将拥有与父ID相同的子女数量,而不是这个,而是让每个孩子都有一次和json, parent_id字段,我可以有:"parent_id": ["1", "2"]
。
我可以创建一个循环,然后在追加一个子节点之前,检查这个子节点是否存在以及是否存在,然后在字段parent_id' s中的列表中添加parent_id。 我可以这样做,但我的查询将继续为每个parent_id为同一个孩子返回一行。我的问题如下,我可以带走所有孩子,并且每个孩子都可以接受所有的parent_id吗?
答案 0 :(得分:1)
这几乎就是SQL的工作方式。但是:你可以在这里利用SQLAlchemy的ORM关系,让SQLA处理"重复数据删除"为你:
students = db.session.query(Child).\
options(joinedload("parents", innerjoin=True)).\
all()
将获取Child对象并在同一查询中预填充父关系。要了解显式连接和连接加载之间的区别,请阅读the zen of joined eager loading。 innerjoin=True
就在那里,因为您的原始查询也执行了一次。那么你可以简单地说:
students_json = {
"children": [
{
"name": s.name,
"id": s.id,
"parent_id": [p.id for p in s.parents]
}
for s in students
]
}
如果您担心返回行的宽度,您也可以提供合适的load_only()
选项:
options(load_only("id", "name"),
joinedload("parents", innerjoin=True).load_only("id"))