classmethod
でself
は、すなわちFoo
クラス自体であるので、あなたのコードが動作しない理由があります。 (これは、従来、self
の代わりにcls
と命名された理由です)。Foo.bars
はを持たないから、Foo.bars
は関係そのものであり、Query
オブジェクトではないからです。
これを書き込む正しい方法は何ですか?これらのシナリオでは、SQLAlchemyの魔法からあなた自身を取り除き、あなたが書く必要があるSQLについて考えることが役に立ちます。簡単な方法はEXISTS
を使用することです:
SELECT * FROM foo
WHERE NOT EXISTS (
SELECT * FROM bar
WHERE bar.foo_id = foo.id AND bar.status != 'ready'
);
またはJOIN
:
SELECT * FROM foo
LEFT JOIN bar ON foo.id = bar.foo_id AND bar.status != 'ready'
WHERE bar.id IS NULL;
これで武装し、それが今、あなたのis_ready
を書くのは簡単です:
class Foo(Base):
@classmethod
def is_ready(cls):
return ~exists(select([Bar.id]).where(and_(Bar.foo_id == cls.id, Bar.status != "ready")))
session.query(Foo).filter(Foo.is_ready())
あなたもそれを回すことができます〜にhybrid_property
:
class Foo(Base):
@hybrid_property
def is_ready(self):
return all(bar.status == "ready" for bar in self.bars)
@is_ready.expression
def is_ready(cls):
bar = Bar.__table__
return ~exists(select([Bar.id]).where(and_(Bar.foo_id == cls.id, Bar.status != "ready")))
session.query(Foo).filter(Foo.is_ready)
JOIN
がclassmethod
またはこのようなhybrid_property
を使用して表現するのが難しいので、あなたが使用できる1つのトリックは.with_transformation
です:
class Foo(Base):
@classmethod
def is_ready(cls):
def _transformer(query):
return query.join(Bar, and_(Foo.id == Bar.foo_id, Bar.status != "ready")).filter(Bar.id.is_(None))
return _transformer
session.query(Foo).with_transformation(Foo.is_ready())
それは素晴らしい作品!しかし私は別の質問があります。なぜ 'is_ready(self)'が '@ hybrid_property'ですか?それは通常のプロパティ '@ property'である可能性があり、私が間違っていないとうまくいくでしょう。 –
@ Overflow012 'hybrid_property'はインスタンスとクラスの両方で動作しますので、' Foo.is_ready'と 'foo.is_ready'の両方を(テーブルの列を使って)フィルターとして、クラスのインスタンスで' foo.is_ready' (メモリにロードされた属性と関係を使用して)。 – univerio