首页 文章

返回重复子节点的SQLAlchemy多对多关系

提问于
浏览
1

我在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的列表中添加parent_id . 我可以这样做,但我的查询将继续为每个parent_id为同一个孩子返回一行 . 我的问题如下,我可以带走所有孩子,每个孩子都需要所有的parent_id吗?

1 回答

  • 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"))
    

相关问题