使用SQLAlchemy表达此查询的最惯用方法是什么?

时间:2014-04-25 22:10:27

标签: python sqlalchemy flask-sqlalchemy

基本上我有一个SQLAlchemy查询,如下所示:

foos = Foo.query.filter(Foo.expiration < cutoff)
valid_foos = []
for foo in foos:
    last_bar = foo.bars.order_by('created_at desc').first()
    if last_bar.state != 'fatal':
        valid_foos.append(foo)

目标是选择第一个相关酒吧状态不是&#34;致命&#34;的所有foos。看起来子查询可能对此有所帮助。但是,我正在努力掌握如何以这种方式表达last_bar = foo.bars.order_by('created_at desc').first()

2 个答案:

答案 0 :(得分:0)

我认为最简单,最通用的方式是使用Hybrid Attributes扩展名。当您按照以下方式扩展模型时:

class Foo(Base):
    __tablename__ = "foo"
    # ...

    @hybrid_property
    def last_bar_state(self):
        _last_bar = self.bars.order_by(Bar.created_at.desc()).first()
        return _last_bar.state

    @last_bar_state.expression
    def _last_bar_state_expression(cls):
        q = (select([Bar.state.label("state")])
                .where(Bar.foo_id == cls.foo_id)
                .order_by(Bar.created_at.desc())
                .limit(1)
                ).label("last_bar_state_sub")
        return q

您可以在内存中以及查询中使用last_bar_state

foos = session.query(Foo).filter(Foo.expiration < cutoff)
foos = foos.filter(Foo.last_bar_state != 'fatal').all()

答案 1 :(得分:0)

使用子查询查找每个Foo的最新Bar。然后在查询Foo时使用它来连接和过滤Bar。

sub = db.session.query(
    Foo.id,
    db.func.max(Bar.created_at).label('latest')
).join(Foo.bars).group_by(Foo.id).subquery()

foos = db.session.query(Foo).join(Bar, db.and_(
    Bar.foo_id == sub.c.id,
    Bar.created_at == sub.c.latest
)).filter(Bar.status != 'fatal').all()

如果没有Bar,则不会选择Foo,您可以使用外部连接。