SqlAlchemy:检查一个对象是否处于任何关系中(or_(object.relationship1.contains(otherObject),object.relationship2.contains(otherObject))

时间:2011-05-25 02:04:13

标签: python sqlalchemy relationship

假设我有一个这样的课程:

class Foo(declarativeBase):
     bars1 = relationship(Bar.Bar, secondary=foos_to_bars1, collection_class=set())
     bars2 = relationship(Bar.Bar, secondary=foos_to_bars2, collection_class=list())

(每个关系都给我“Bar”s具有一定的条件)。在某个时刻,我想在任何关系中得到“Foo”的实例,它们都有一个“bar”(Bar.Bar的实例)。

如果我尝试:

def inAnyBar(bar)
   query(Foo).filter(or_(Foo.bars1.contains(bar), Foo.bars2.contains(bar)).all()

我得到一个空的结果。

看起来(对我而言)我正在做类似的事情:

query(Foo).join(Foo.bars1).filter(Foo.bars1.contains(bar)).\
join(Foo.bars2).filter(Foo.bars1.contains(bar))

由于Foo.bars1不包含bar,因此第二个过滤器会显示空结果。

我已经能够找到子查询的解决方法(子查询中的每个连接+过滤器,然后是或所有子查询),但我想知道是否有更好的方法来实现...

我发现了这个: http://techspot.zzzeek.org/2008/09/09/selecting-booleans/

这就是我想要做的事情,但它适用于SqlAlchemy 0.5而且我(几乎)确定使用SqlAlchemy 0.6.6有一种“更清洁”的方式来做这件事

谢谢!

1 个答案:

答案 0 :(得分:4)

你是对的,session.query(Foo).filter(Foo.bars1.contains(bar)|Foo.bars2.contains(bar))产生以下SQL:

SELECT "Foo".id AS "Foo_id" 
FROM "Foo", foos_to_bars1 AS foos_to_bars1_1, foos_to_bars2 AS foos_to_bars2_1 
WHERE "Foo".id = foos_to_bars1_1.foo AND ? = foos_to_bars1_1.bar OR 
"Foo".id = foos_to_bars2_1.foo AND ? = foos_to_bars2_1.bar

当其中一个secondary表为空时返回错误的结果。看起来像是SQLAlchemy中的一个错误。但是用contains()替换any()修复了问题(它使用了EXISTS子查询):

session.query(Foo).filter(Foo.bars1.any(id=bar.id)|Foo.bars2.any(id=bar.id))

您也可以明确指定OUTER JOIN:

Bar1 = aliased(Bar)
Bar2 = aliased(Bar)
session.query(Foo).outerjoin((Bar1, Foo.bars1)).outerjoin((Bar2, Foo.bars2))\
    .filter((Bar1.id==bar.id)|(Bar2.id==bar.id))