将 SQLAlchemy ORM 与 sql 核心表达式中的对象连接起来?
connect SQLAlchemy ORM with the objects from sql core expression?
我必须使用 SQLalchemy Core 表达式来获取对象,因为 ORM 做不到 "update and returning"。 (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
。
如何将 sql 表达式中的 RowProxy
对象放入 ORM 的恒等映射中
?
我不确定是否有一种直接的方法来执行您所描述的操作,这主要是构建一个直接映射到数据库条目但不通过 ORM 执行查询的 ORM 对象。
我的直觉是,天真的方法(只需使用数据库中的值构建 ORM 对象)只会创建具有相同值的另一行(或由于唯一性约束而失败)。
更标准的方法是通过 ORM 首先查询行,然后从该 ORM 对象更新数据库。
user = User.query.filter(User.user_attribute == 'foo').one()
user.some_value = 'bar'
session.add(user)
session.commit()
我不确定您是否有一些限制阻止您使用该模式。该文档通过类似 examples
简单案例:
可能的快速解决方案:从 RowProxy
的 kwargs
构造对象,因为它们是类对象。
给定:
rowproxy = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
我们或许可以做到:
user = User(**dict(rowproxy.items()))
rowproxy.items()
returns 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
class 中时,我们可能会收到如下错误: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
返回的值,除了允许类似对象的访问外,还允许类似字典的访问:
kwargs = {a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
现在我们可以做:
user = User(**kwargs)
勘误表:
- 您可能希望在调用
update().returning()
后立即 session.commit()
以防止更改与永久存储在数据库中时的长时间延迟。稍后无需 session.add(user)
- 您已经 updated()
并且只需要 commit()
该交易
object
是Python中的关键词,尽量不要踩;这样做你会得到一些非常奇怪的行为;这就是为什么我重命名为 rowproxy
.
我必须使用 SQLalchemy Core 表达式来获取对象,因为 ORM 做不到 "update and returning"。 (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
。
如何将 sql 表达式中的 RowProxy
对象放入 ORM 的恒等映射中
?
我不确定是否有一种直接的方法来执行您所描述的操作,这主要是构建一个直接映射到数据库条目但不通过 ORM 执行查询的 ORM 对象。
我的直觉是,天真的方法(只需使用数据库中的值构建 ORM 对象)只会创建具有相同值的另一行(或由于唯一性约束而失败)。
更标准的方法是通过 ORM 首先查询行,然后从该 ORM 对象更新数据库。
user = User.query.filter(User.user_attribute == 'foo').one()
user.some_value = 'bar'
session.add(user)
session.commit()
我不确定您是否有一些限制阻止您使用该模式。该文档通过类似 examples
简单案例:
可能的快速解决方案:从 RowProxy
的 kwargs
构造对象,因为它们是类对象。
给定:
rowproxy = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
我们或许可以做到:
user = User(**dict(rowproxy.items()))
rowproxy.items()
returns 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
class 中时,我们可能会收到如下错误: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
返回的值,除了允许类似对象的访问外,还允许类似字典的访问:
kwargs = {a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
现在我们可以做:
user = User(**kwargs)
勘误表:
- 您可能希望在调用
update().returning()
后立即session.commit()
以防止更改与永久存储在数据库中时的长时间延迟。稍后无需session.add(user)
- 您已经updated()
并且只需要commit()
该交易 object
是Python中的关键词,尽量不要踩;这样做你会得到一些非常奇怪的行为;这就是为什么我重命名为rowproxy
.