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,则可以像示例中那样使用常规联接。
您可以像上面那样动态加载不同的关系,也可以事先通过对关系本身设置加载设置来加载不同的关系。您可以在下面阅读这些内容:
我不熟悉将 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,则可以像示例中那样使用常规联接。
您可以像上面那样动态加载不同的关系,也可以事先通过对关系本身设置加载设置来加载不同的关系。您可以在下面阅读这些内容: