【问题标题】:SQLAlchemy Many To Many relationship returning duplicate childrenSQLAlchemy 多对多关系返回重复的孩子
【发布时间】:2018-05-03 15:42:34
【问题描述】:

我在 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')

最后是一张关系表:

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')))

因此,一个孩子可以有 1 个或多个父母,而一个父母可以有 1 个或多个孩子。

现在假设我想获取所有孩子并将它们作为 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 的列表中添加 parent_id。 我可以这样做,但我的查询将继续为每个 parent_id 的同一个孩子返回一行。我的问题如下,我可以带走所有孩子并为每个孩子带走所有 parents_id 吗?

【问题讨论】:

    标签: python json sqlalchemy flask-sqlalchemy


    【解决方案1】:

    这就是 SQL 的工作原理。但是:您可以在这里利用 SQLAlchemy 的 ORM 关系,让 SQLA 为您处理“重复数据删除”:

    students = db.session.query(Child).\
        options(joinedload("parents", innerjoin=True)).\
        all()
    

    它将获取子对象并在同一查询中预填充父关系。要了解显式联接和联接负载之间的区别,请阅读the zen of joined eager loadinginnerjoin=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"))
    

    【讨论】:

      猜你喜欢
      • 2014-03-12
      • 1970-01-01
      • 2015-10-21
      • 2012-02-08
      • 2014-05-19
      • 1970-01-01
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多