You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SQLAlchemy更新后,如何通过returning获取计算字段新值?

解决SQLAlchemy异步ORM中Computed字段更新后会话内值不刷新的问题

问题根源

SQLAlchemy的会话(Session)会缓存实例对象,Computed类型的计算字段默认不会自动同步数据库更新后的新值——哪怕用returning子句返回了数据,ORM也可能没把新值更新到缓存的实例上,导致同会话内不管怎么查,读的都是旧缓存数据,只有新开会话才会重新从数据库拉取最新值。

具体解决办法

1. 显式返回Computed字段并手动同步实例

更新操作时,把total_cost明确加入returning子句,拿到返回的新数据后,手动覆盖会话缓存实例的对应属性:

from sqlalchemy import update

# 执行更新,指定返回需要的字段
result = await session.execute(
    update(Tablichka)
    .where(Tablichka.id == target_id)
    .values(quantity=15, price=25)
    .returning(Tablichka.id, Tablichka.quantity, Tablichka.price, Tablichka.total_cost)
)
updated_data = result.one()

# 从会话中获取实例,同步新值
target_instance = await session.get(Tablichka, updated_data.id)
target_instance.quantity = updated_data.quantity
target_instance.price = updated_data.price
target_instance.total_cost = updated_data.total_cost

2. 用Session.refresh()强制从数据库同步

更新完成后,调用session.refresh()方法,强制ORM从数据库重新加载实例的所有属性,包括Computed字段:

# 执行更新操作
await session.execute(
    update(Tablichka)
    .where(Tablichka.id == target_id)
    .values(quantity=15, price=25)
)
await session.commit()

# 获取实例并强制刷新
target_instance = await session.get(Tablichka, target_id)
await session.refresh(target_instance)
# 此时target_instance.total_cost就是数据库里的最新值

如果是在未提交的事务中,refresh()也能读取到数据库中未提交的修改(具体取决于数据库的隔离级别)。

3. 给Computed字段配置onupdate自动计算

定义模型时,给total_cost字段添加onupdate参数,指定当依赖的quantity或price更新时,自动计算并更新内存中的total_cost值:

from sqlalchemy import Column, Integer, Numeric, Computed

class Tablichka(Base):
    __tablename__ = "tablichka"
    id = Column(Integer, primary_key=True)
    quantity = Column(Integer)
    price = Column(Numeric(10, 2))
    total_cost = Column(
        Numeric(10, 2),
        Computed("quantity * price"),
        onupdate=lambda ctx: ctx.current_parameters.get("quantity") * ctx.current_parameters.get("price")
    )

这样更新quantity或price时,ORM会自动同步total_cost的内存值,不用额外手动操作。

4. 临时禁用实例缓存(仅调试用)

如果只是临时调试,可以在查询时用populate_existing(),强制忽略会话缓存,直接从数据库读最新数据:

target_instance = await session.query(Tablichka).filter_by(id=target_id).populate_existing().one()

不推荐长期用这个方法,会影响ORM的缓存性能。


内容的提问来源于stack exchange,提问作者Александр Десятов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 06:27:40