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

Pav*_*sko 3 python sqlalchemy

我定义了以下映射类

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)
Run Code Online (Sandbox Code Playgroud)

DB 中存储了这些对象:

a1 = A(number_a = 1)
a2 = A(number_a = 2)
b1 = B(number_b = 50, a = a2)
b2 = B(number_b = 51, a = a2)
Run Code Online (Sandbox Code Playgroud)

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

result = session.query(A).join(B).filter(B.number_b == 51).all()
Run Code Online (Sandbox Code Playgroud)

所以现在我想result[0].b_collection尊重过滤表达式并且不包含B实例with number_b = 50。所以我的预期输出是:

for a in result:
    for b in a.b_collection:
        print(b.number_b)
Run Code Online (Sandbox Code Playgroud)

将会:

51
Run Code Online (Sandbox Code Playgroud)

然而,迭代a.b_collection始终会发出一个新查询并将两个B对象加载到 中b_collection,因此结果是

50
51
Run Code Online (Sandbox Code Playgroud)

这是我不想得到的。

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

谢谢你的回复。

van*_*van 5

使用 执行此操作contains_eager,但请注意,您正在欺骗SQL Alchemy,因此不要重用此UnitOfWork来执行常规关系相关任务:

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