FastAPI + SqlAlchemy:左连接

FastAPI + SqlAlchemy: Left join

我不熟悉将 FastAPI 和 SqlAlchemy 与 PostgreSQL 结合使用。我一直致力于创建一些模型,开始时效果很好。

class Parent(Base):
  __tablename__ = "parents"
  uid = Column(Integer, primary_key=True)
  children = relationship("Child", back_populates="parent")

class Child(Base):
  __tablename__ = "children"
  uid = Column(Integer, primary_key=True)
  parent_id = Column(Integer, ForeignKey("parents.uid"))
  parent = relationship("Parent", backpopulates="children")

这部分工作如我所料,我可以创建 Parent 和 Child objects,其中 Child 模型具有 parent_id 字段引用 Parent.uid 字段的外键。 我的问题是当我现在尝试获取 parent 并且它在查询中是 children 时。为此,我使用 SqlAlchemy 查询函数:

  session.query(Parent).outerjoin(Child).all()

在我看来,这应该给我一个看起来像这样的 parent object:{ uid: 1, children: [{ uid: 111 }] }。但是我得到的只是:{ uid: 1 }。虽然它不会引发错误,但它不会向我显示 child 数据。当我查看 SqlAlchemy 使用的查询(使用 query.statement.compile(compile_kwargs={"literal_binds": True}))时,我得到:

SELECT parent.uid, child.uid as uid_1 FROM parents LEFT OUTER JOIN children ON parent.uid = child.parent_id;

这是我所期望的,当我 运行 在 psql shell 中这样做时,我得到了预期的结果:

 uid | uid_1
-----+-------
   1 |   111

我尝试了各种不同的方式来定义关系,包括在连接和模型声明中(backrefs,声明显式连接,例如 .outerjoin(child, child.parent_id == parent.uid,等等),但我没有做任何事情给我输出我正在从 SqlAlchemy 查询中寻找。非常感谢任何帮助。

在使用 ORM 时,通常您会像这样引用 parent 之外的关系:

for parent in session.query(Parent).all():
    for child in parent.children:
        # do something here
        pass

每次您必须为 parent 获取 children(使用延迟加载时)这不是您想要的,这会执行查询。

有很多加载策略可以“加载”children。模拟您所描述的内容的是联合负载,如下所示:

from sqlalchemy.orm import joined_load

q = session.query(Parent).options(joinedload(Parent.children))
for parent in q.all():
    for child in parent.children:
        # these children should already be loaded
        pass

如果您需要根据 child 列过滤 parent,则可以像示例中那样使用常规联接。

您可以像上面那样动态加载不同的关系,也可以事先通过对关系本身设置加载设置来加载不同的关系。您可以在下面阅读这些内容: