gpt4 book ai didi

python - 连接上的过滤器不会传播到相关的 orm.relations

转载 作者:太空宇宙 更新时间:2023-11-03 18:48:39 26 4
gpt4 key购买 nike

在这里定义一些基本结构:

class A( Base ):

__tablename__ = 'a'
id = Column( types.Integer(), primary_key = True )

abs = orm.relation( 'AB', lazy='joined' )

class AB( Base ):

__tablename__ = 'ab'
id = Column( types.Integer(), primary_key = True )
a_id = Column( types.Integer(), ForeignKey( 'a.id' ) )
b_id = Column( types.Integer(), ForeignKey( 'b.id' ) )

a = orm.relation( 'A' )
b = orm.relation( 'B', lazy='joined' )

class B( Base ):

__tablename__ = 'b'
id = Column( types.Integer(), primary_key = True )

bas = orm.relation( 'AB' )

现在假设我有一个 A 和多个与其相关的 B(例如 A.id = 1),我想基于这些B进行过滤。我执行以下查询:

a = db.session.query( A ).join( A.abs ).filter( AB.b_id = 1, A.id = 1 ).first()

此时,我期望 len( a.abs ) == 1,但事实并非如此。换句话说,应用于连接的过滤器不会传播到 orm.relation。我如何获得这种行为?

最佳答案

The Zen of Eager Loading 中描述了此问题的原因。归结为:您的查询中将有两个不同的联接。一个用于构建要过滤的正确连接(这是您使用 .join(A.abs) 生成的),另一个用于加载关系(ORM 根据 自动插入该关系) >lazy="joined",否则会在访问时查询)。

现在有几种方法可以解决这个问题。但首先你应该考虑一下你真正想要什么。因为当您说A.abs时,您实际上是在说“所有属于该A的AB条目”。但是,当您指定单个 b_id 时,这不是您想要的,因为这不是此关系所代表的意思。所以这是干净的方法:

db.session.query(A, AB).join(A.abs).filter(AB.b_id = 1, A.id = 1)

现在您将获得 AB 作为查询中第二个返回的对象。这是正确的做法,因为在 A.abs 中只有一个 AB 实际上会对 ORM 撒谎:这里不是这样的(而且它可能会破坏东西) 。但是,如果您坚持这样做,这是可能的。您可以使用 sqlalchemy.orm.contains_eager 禁用双连接。 :

db.session.query(A).join(A.abs).options(contains_eager(A.abs)).filter(AB.b_id = 1, A.id = 1)

这将生成一个 A.abs,其中只有一个具有 b_id = 1 的条目。然而,正如已经指出的,这不是一个好的解决方案,也不是您应该做的。

作为额外提示,我建议您在引擎中打开 echo=True 甚至 echo="debug" 以确保您看到正在执行的查询。如果您查看原始查询,则会在同一个表上看到两个联接。

关于python - 连接上的过滤器不会传播到相关的 orm.relations,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18876692/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com