Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 联接上的筛选器不会传播到相关的orm.relations_Python_Sqlalchemy - Fatal编程技术网

Python 联接上的筛选器不会传播到相关的orm.relations

Python 联接上的筛选器不会传播到相关的orm.relations,python,sqlalchemy,Python,Sqlalchemy,在此定义一些基本结构: 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(

在此定义一些基本结构:

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
s与其相关(比如
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。如何获得此行为?

中描述了此问题的原因,归结为:查询中将有两个不同的联接。一个用于构建要筛选的正确联接(这是您使用
.join(A.abs)
生成的联接),另一个用于加载关系(ORM根据
lazy=“joined”
自动插入该关系,否则它将在acess上查询它)

现在有几种方法可以解决这个问题。但首先你应该考虑你真正想要什么。因为当你说
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:这里不是这样(它可能会破坏东西)。然而,如果你坚持这样做是可能的。您可以通过以下方式禁用双连接:

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


作为补充提示,我建议您在引擎中启用
echo=True
甚至
echo=“debug”
,以确保看到正在执行的查询。如果查看原始查询,那么将在同一个表上看到两个联接。

中描述了此问题的原因,归结起来就是:查询中将有两个不同的联接。一个用于构建要筛选的正确联接(这是您使用
.join(A.abs)
生成的联接),另一个用于加载关系(ORM根据
lazy=“joined”
自动插入该关系,否则它将在acess上查询它)

现在有几种方法可以解决这个问题。但首先你应该考虑你真正想要什么。因为当你说
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:这里不是这样(它可能会破坏东西)。然而,如果你坚持这样做是可能的。您可以通过以下方式禁用双连接:

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


作为补充提示,我建议您在引擎中启用
echo=True
甚至
echo=“debug”
,以确保看到正在执行的查询。如果查看原始查询,那么将在同一个表上看到两个联接。

对于第一个解决方案,我还需要手动将联接条件添加到筛选器中,不是吗?例如
db.session.query(A,AB).filter(AB.A_id=A.id,AB.b_id=1,A.id=1)
如果省略了
join
部分,则必须手动执行此操作,否则SQLAlchemy可以为您执行此操作。对于第一个解决方案,我还需要手动将连接条件添加到过滤器中,不是吗?例如
db.session.query(A,AB).filter(AB.A_id=A.id,AB.b_id=1,A.id=1)
如果省略了
join
部分,则必须手动执行此操作,否则SQLAlchemy可以为您执行此操作。