SQLAlchemy 多对一连接

1 投票
1 回答
2068 浏览
提问于 2025-04-18 17:11

我在使用 SQLAlchemy 的时候,有两个 SQL 表之间是多对一的关系。举个例子:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    child_id = Column(Integer, ForeignKey('child.id'))
    child = relationship("Child")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))

我想做的是把 Child 类的信息添加到父类中。我尝试了一下 join 查询:

result = session.query(Parent).join(Child).all()

虽然这个查询把合适的 Child 对象添加到了 Parent 对象的 parent.child 里,但它只返回了每个孩子对应的第一个父亲。也就是说,我的数据库里有四个父亲和两个孩子,而这个查询只返回了父亲 1 和 3。我该怎么修改这个查询才能返回所有四个父亲呢?另外,如果我只想把孩子的名字添加到父亲里,而不是整个孩子对象,像 parent.child_name 这样,我该怎么做呢?

1 个回答

1

如何在连接子项时获取所有父项

问题在于,有些父项没有子项,所以用普通的连接方式会把这些父项排除掉。你应该使用外连接,这样就能把所有父项都包括进来。此外,单纯地添加连接并不会自动加载子项。你需要指定 contains_eagerjoinedload 来确保在加载父项时也能把子项一起加载出来。

# use contains_eager when you are joining and filtering on the relationship already
session.query(Parent).join(Parent.child).filter(Child.name == 'Max').options(contains_eager(Parent.child))

# use joinedload when you do not need to join and filter, but still want to load the relationship
session.query(Parent).options(joinedload(Parent.child))

如何将 child_name 添加到父项

你需要使用一个叫做 关联代理 的东西。

from sqlalchemy.ext.associationproxy import association_proxy

class Parent(Base):
    child = relationship('Child')
    child_name = association_proxy('child', 'name')

# you can filter queries with proxies:
session.query(Parent).filter(Parent.child_name == 'Min')

使用关联代理可以做一些很酷的事情,记得去看看文档了解更多信息。

撰写回答