【问题标题】:How to annotate a function element with a FROM object in SQLAlchemy如何在 SQLAlchemy 中使用 FROM 对象注释函数元素
【发布时间】:2017-07-09 17:42:49
【问题描述】:

在回答 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))

问题是

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() 显式添加 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 作为 FROM 对象。或者换句话说,只是一种将 Foo 作为from_obj 添加到函数表达式或标量子查询的方法,以便内部选择可以使用它。

【问题讨论】:

    标签: python postgresql sqlalchemy


    【解决方案1】:

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

    【讨论】:

    • 这是一个好主意,虽然CompoundSelect(如except_() 生成)没有select_from() 方法。我也不完全确定它会如何发挥作用,如果您将“select from”添加到将被标记为标量子查询并包装在 ARRAY() 构造函数中的语句中。
    • 如果前面的评论不清楚(有点冗长),这不起作用。
    • 感谢您的 cmets。我不确定它会 100% 工作。也许您可以尝试改进我的答案?
    猜你喜欢
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多