我必须使用 SQLalchemy Core 表达式来获取对象,因为 ORM 无法执行“更新和返回”。 (ORM 中的更新没有 returning
)
from sqlalchemy import update
class User(ORMBase):
...
# pure sql expression, the object returned is not ORM object.
# the object is a RowProxy.
object = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
什么时候
db_session.add(object)
它报告
UnmappedInstanceError: Class 'sqlalchemy.engine.result.RowProxy' is not mapped
。如何将
RowProxy
对象从 sql 表达式放入 ORM 的标识映射中?
最佳答案
简单案例:
可能的快速解决方案:从 kwargs
的 RowProxy
构造对象,因为它们类似于对象。
鉴于:
rowproxy = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
我们或许能够做到:
user = User(**dict(rowproxy.items()))
rowproxy.items()
返回 tuples
对的 key-value
; dict(...)
将 tuples
转换为实际的 key-value
对; User(...)
将 kwargs
作为 model
属性名称。更难的情况:
但是,如果您有一个
model
,其中 attribute names
之一与 SQL table
column name
不完全相同呢?例如。就像是:class User(ORMBase):
# etc...
user_id = Column(name='id', etc)
当我们尝试将
rowproxy
解包到 User
类中时,我们可能会得到如下错误: TypeError: 'id' is an invalid keyword argument for User
(因为它期待的是 user_id
)。现在它变脏了:我们应该围绕
mapper
如何从 table
属性获取 model
属性,反之亦然:kw_map = {a.key: a.class_attribute.name for a in User.__mapper__.attrs}
这里,
a.key
是 model attribute
(和 kwarg
),而 a.class_attribute.name
是 table attribute
。这给了我们类似的东西:{
"user_id": "id"
}
好吧,我们想要真正提供我们从
rowproxy
返回的值,它除了允许类对象访问还允许类 dict 访问:kwargs = {a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
现在我们可以这样做:
user = User(**kwargs)
勘误表:
session.commit()
后立即使用 update().returning()
以防止更改与永久存储在数据库中时的长时间延迟。以后不需要 session.add(user)
- 你已经 updated()
并且只需要 commit()
那个交易 object
是 Python 中的关键字,所以尽量不要踩到它;你可能会得到一些非常奇怪的行为;这就是我重命名为 rowproxy
的原因。 关于python - 将 SQLAlchemy ORM 与 sql 核心表达式中的对象连接起来?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41517779/