这很简单。这按预期工作:
>>> db.session.query(SomeModel).all()[0]
SomeModel(41330029-f21e-4022-aed5-e45e61ada399
但是如果我尝试添加另一列,我会得到一个元组:
>>> db.session.query(SomeModel, some_expression.label('foo')).all()[0]
(SomeModel(41330029-f21e-4022-aed5-e45e61ada399), None)
如何获得平坦的结果?也就是说,一个
SomeModel
里面有一个 foo
属性,而不是作为同级?
column_property
添加到 SomeModel
,在这种情况下,它将始终是其实例的属性。如果您只是偶尔需要它,那么只需在查询执行后将其设置为属性即可:
results = db.session.query(SomeModel, some_expression.label('foo')).all()
for mod, att in results:
mod.foo = att # or: setattr(mod, "foo", att)
results = [mod for mod, _attr in results]
要在运行时将任意表达式的结果添加到 ORM 实体,请使用 with_expression(请参阅将任意 SQL 表达式加载到对象上 中的文档以完整了解此行为)。请注意,实体类必须使用 query_expression() 定义占位符属性。此示例演示如何添加将
User
实例的 name
属性大写的列。
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import Mapped, mapped_column
engine = sa.create_engine('postgresql+psycopg2:///test', echo=True)
class Base(orm.DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(unique=True)
# Define an attribute to hold the result of the expression.
upper_name: Mapped[str] = orm.query_expression()
Base.metadata.create_all(engine)
with orm.Session(engine) as s:
q = sa.select(User).options(
orm.with_expression(User.upper_name, sa.func.upper(User.name))
)
for user in s.scalars(q):
print(user.name, user.upper_name)
如果没有 query_expression()
选项应用于查询,则
NULL
默认为 with_expression()
;它接受 default_expr
参数来覆盖此默认值,例如 query_expression(default_expr=sa.literal('FOO'))
。
如果不希望在每个查询中出现占位符属性,则可以使用 deferred:
来阻止它...
class User(Base):
...
upper_name = orm.deferred(orm.query_expression())
对查询应用
with_expression
选项似乎足以 undefer 属性;不需要显式调用 undefer
。