添加列进行查询,返回 SQLAlchemy 中的映射类内部

问题描述 投票:0回答:2

这很简单。这按预期工作:

>>> 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
属性,而不是作为同级?

python sqlalchemy flask-sqlalchemy
2个回答
3
投票

对于简单的表达式,我会使用

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]

0
投票

要在运行时将任意表达式的结果添加到 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

© www.soinside.com 2019 - 2024. All rights reserved.