具有特定列的 SqlAlchemy 2.x 使 scalars() 返回非 orm 对象

Dra*_*els 6 python sqlalchemy

这个问题可能是我不理解(新)sqlalchemy 的架构,通常我使用这样的代码:

query = select(models.Organization).where(
    models.Organization.organization_id == organization_id
)
result = await self.session.execute(query)

return result.scalars().all()
Run Code Online (Sandbox Code Playgroud)

工作正常,我得到了模型列表(如果有的话)。

对于仅包含特定列的查询:

query = (
    select(
        models.Payment.organization_id,
        models.Payment.id,
        models.Payment.payment_type,
    )
    .where(
        models.Payment.is_cleared.is_(True),
    )
    .limit(10)
)

result = await self.session.execute(query)

return result.scalars().all()
Run Code Online (Sandbox Code Playgroud)

我只得到第一行第一列。似乎相同: https: //docs.sqlalchemy.org/en/14/core/connections.html ?highlight=scalar#sqlalchemy.engine.Result.scalar

到目前为止,我的理解是,在新的 sqlalchemy 中,我们应该始终调用scalars()查询,如下所述:https: //docs.sqlalchemy.org/en/14/changelog/migration_20.html#migration-orm-usage

但对于特定的列,我们似乎根本不能使用 scalars() 。更令人困惑的是,result.scalars()返回sqlalchemy.engine.result.ScalarResult具有 fetchmany()、fechall() 以及其他我无法以任何有意义的方式迭代的方法。

我的问题是,我不明白什么?

Gor*_*son 16

到目前为止,我的理解是,在新的 sqlalchemy 中,我们应该始终在查询上调用 scalars()

这在很大程度上是正确的,但仅适用于返回整个 ORM 对象的查询。只是一个普通的.execute()

    query = select(Payment)

    results = sess.execute(query).all()
    print(results)  # [(Payment(id=1),), (Payment(id=2),)]
    print(type(results[0]))  # <class 'sqlalchemy.engine.row.Row'>
Run Code Online (Sandbox Code Playgroud)

返回一个对象列表Row,每个对象包含一个 ORM 对象。用户发现这很尴尬,因为他们需要从对象中解压 ORM 对象Row。所以.scalars()现在推荐

    results = sess.scalars(query).all()
    print(results)  # [Payment(id=1), Payment(id=2)]
    print(type(results[0]))  # <class '__main__.Payment'>
Run Code Online (Sandbox Code Playgroud)

但是,对于返回单个属性(列)的查询,我们不想使用,.scalars()因为这只会为我们提供每行的一列,通常是第一列

    query = select(
        Payment.id,
        Payment.organization_id,
        Payment.payment_type,
    )

    results = sess.scalars(query).all()
    print(results)  # [1, 2]
Run Code Online (Sandbox Code Playgroud)

相反,我们想使用常规,.execute()这样我们就可以看到所有列

    results = sess.execute(query).all()
    print(results)  # [(1, 123, None), (2, 234, None)]
Run Code Online (Sandbox Code Playgroud)

笔记:

  • .scalars()在这两种情况下都做同样的事情:返回一个列表,其中包含每行的单个(标量)值(默认值为索引= 0)。

  • sess.scalars()是首选构造。它只是 的简写sess.execute().scalars()