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

时间:2015-02-23 16:28:48

标签: 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)

这些对象存储在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)

我需要的是通过仅发出一个查询来查询关系,以便仅通过该查询的结果预加载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

这是我不想要的。

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

感谢您的回复。

1 个答案:

答案 0 :(得分:2)

使用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()