SQLAlchemy更新后出现奇怪错误:'list'对象没有'_all_columns'属性

1 投票
1 回答
1161 浏览
提问于 2025-04-18 14:34

这是我问题的简化版本:

subquery = (select(['latitude'])
            .select_from(func.unnest(func.array_agg(Room.latitude))
                         .alias('latitude')).limit(1).as_scalar())
Room.query.with_entities(Room.building, subquery).group_by(Room.building).all()

执行时我在SQLAlchemy内部遇到了一个错误:

  File ".../sqlalchemy/sql/selectable.py", line 429, in columns
    self._populate_column_collection()
  File ".../sqlalchemy/sql/selectable.py", line 992, in _populate_column_collection
    for col in self.element.columns._all_columns:
AttributeError: 'list' object has no attribute '_all_columns'

在调试器中查看时,我看到了这个:

>>> self.element
<sqlalchemy.sql.functions.Function at 0x7f72d4fcae50; unnest>
>>> str(self.element)
'unnest(array_agg(rooms.id))'
>>> self.element.columns
[<sqlalchemy.sql.functions.Function at 0x7f72d4fcae50; unnest>]

问题始于SQLAlchemy 0.9.4;在0.9.3版本中一切正常。

在SQLAlchemy 0.9.3中运行时,执行了以下查询(这是预期的结果):

SELECT rooms.building AS rooms_building,
       (SELECT latitude
        FROM unnest(array_agg(rooms.latitude)) AS latitude
        LIMIT 1) AS anon_1
FROM rooms
GROUP BY rooms.building

我是在做错什么,还是这是SQLAlchemy的一个bug?

1 个回答

0

这其实是SQLAlchemy里的一个bug:https://bitbucket.org/zzzeek/sqlalchemy/issue/3137/decide-what-funcxyz-alias-should-do

func.foo().alias() 本来应该和 func.foo().select().alias() 是一样的,但在这个情况下,这样做会导致多一层嵌套,这是我们不想要的。所以要修正这个API,可能需要等到1.0版本,除非我能确定 func.foo().alias() 现在完全不能用。

根据SQLAlchemy开发者的说法,正确的做法是这样的:

subquery = (select(['*']).select_from(
                func.unnest(func.array_agg(Room.latitude)))
            .limit(1)
            .as_scalar())

很可能下一个版本(我猜是0.9.8)会恢复旧的行为:

我会恢复旧的行为,但现在请使用 select(['*'])。这个列是没有名字的。PG根据FROM中的别名来给列命名的行为有点神奇(例如,如果函数返回多个列,它就会忽略那个名字,使用函数报告的名字?)

撰写回答