在 SQLAlchemy ORM 中仅加载连接行的子集

Load only subset of joined rows in SQLAlchemy ORM

我有以下映射 类 定义

class A(Base):
    __tablename__ = "a"
    id = sqla.Column(sqla.Integer, primary_key = True)
    number_a = sqla.Column(sqla.Integer)
    b_collection = relationship('B', backref = backref('a'))

class B(Base):
    __tablename__ = "b"
    id = sqla.Column(sqla.Integer, primary_key = True)
    id_a = sqla.Column(sqla.Integer, sqla.ForeignKey('a.id'))
    number_b = sqla.Column(sqla.Integer)

数据库中存储了这些对象:

a1 = A(number_a = 1)
a2 = A(number_a = 2)
b1 = B(number_b = 50, a = a2)
b2 = B(number_b = 51, a = a2)

我需要的是通过仅发出一个查询来查询关系,以便它仅通过该查询的结果预加载 b_collection

result = session.query(A).join(B).filter(B.number_b == 51).all()

所以现在我希望 result[0].b_collection 遵守过滤表达式并且不包括 B 实例 with number_b = 50。所以我的预期输出:

for a in result:
    for b in a.b_collection:
        print(b.number_b)

将是:

51

但是遍历 a.b_collection 总是会发出一个新查询并将两个 B 对象加载到 b_collection 中,因此结果是

50
51

这是我不想得到的。

如何强制原始查询加载所有对象并根据给定的过滤条件填充关系集合?

感谢您的回复。

使用 contains_eager 执行此操作,但请注意您在 欺骗 SQL 炼金术,因此不要重复使用此 UnitOfWork 做常规关系相关的任务:

result = (
    session.query(A)
    .join(B)
    .filter(B.number_b == 51)
    .options(contains_eager(A.b_collection))  # this is the key
    ).all()