如何用sqlalchemy中的对象注释函数元素



在回答另一个问题时,我碰到了一个墙,试图产生一个将返回函数表达式包裹标量副标的混合属性,该标量从封闭的查询中从对象中关联所有的标量,但它'如果封闭查询中没有其他表达式提供了与与。

给定玩具模型定义

class Foo(Base):
    __tablename__ = 'foo'
    foo_id = Column(Integer, primary_key=True, autoincrement=True)
    bar = Column(postgresql.ARRAY(Integer))
    baz = Column(postgresql.ARRAY(Integer))
    @hybrid_property
    def bar_sans_baz(self):
        return list(set(self.bar).difference(self.baz))
    @bar_sans_baz.expression
    def bar_sans_baz(cls):
        bar = func.unnest(cls.bar).select().correlate(cls)
        baz = func.unnest(cls.baz).select().correlate(cls)
        stmt = bar.except_(baz)
        # Uses `func` generic as ARRAY() constructor
        return func.array(stmt.as_scalar(),
                          type_=postgresql.ARRAY(Integer))

问题是

session.query(Foo.bar_sans_baz)

导致

SELECT array((SELECT unnest(foo.bar) AS unnest_1 
              FROM foo EXCEPT SELECT unnest(foo.baz) AS unnest_2 
              FROM foo)) AS bar_sans_baz

由于它在封闭查询中没有任何相关性。一种简单的补救措施是使用select_from()明确添加来自对象:

session.query(Foo.bar_sans_baz).select_from(Foo)

,结果查询是所需的

SELECT array((SELECT unnest(foo.bar) AS unnest_1
              EXCEPT SELECT unnest(foo.baz) AS unnest_2)) AS bar_sans_baz 
FROM foo

在工作时,它会增加心理开销,因为您必须记住添加select_from(Foo),如果仅选择混合属性。这不是问题,如果其他选择项目提供 foo

In [105]: print(session.query(Foo.bar_sans_baz, Foo.foo_id))
SELECT array((SELECT unnest(foo.bar) AS unnest_1 EXCEPT SELECT unnest(foo.baz) AS unnest_2)) AS bar_sans_baz, foo.foo_id AS foo_foo_id 
FROM foo

是否有一种方法可以注释返回的函数表达式func.array(...)或内部标量子查询,以便如果没有其他表达式提供它,它将提供 foo 作为来自对象的 foo 。或换句话说,仅将 foo 作为 from_obj添加到函数表达式或标量子查询的一种方法。

我想知道为什么您不会在expression中明确添加.select_from定义:

@bar_sans_baz.expression
def bar_sans_baz(cls):
    bar = func.unnest(cls.bar).select().correlate(cls)
    baz = func.unnest(cls.baz).select().correlate(cls)
    stmt = bar.except_(baz).select_from(cls.__tablename__)
    # Uses `func` generic as ARRAY() constructor
    return func.array(stmt.as_scalar(),
                      type_=postgresql.ARRAY(Integer))

最新更新