如何在SQLAlchemy中用FROM对象注释函数元素

2024-04-27 16:47:03 发布

您现在位置:Python中文网/ 问答频道 /正文

在回答another question时,我遇到了一个问题,试图生成一个hybrid property,它将返回一个function expression的标量子查询,该标量子查询与封闭查询中的所有FROM对象相关联,但如果封闭查询中没有其他表达式提供要关联的表,则它仍然会提供FROM对象。在

给出一个玩具模型的定义

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))

问题是

^{pr2}$

结果

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

因为它在封闭查询中没有可关联的内容。一个简单的补救方法是使用^{}显式添加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)。这不是问题,如果任何其他select项提供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作为FROM对象提供。或者换句话说,只是一种将Foo作为from_obj添加到函数表达式或标量子查询的方法,这样内部select就可以使用它。在


Tags: 对象fromfooas量子barbazarray
1条回答
网友
1楼 · 发布于 2024-04-27 16:47:03

我想知道您为什么不在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))

相关问题 更多 >