SQLAlchemy ORM中使用on_conflict_do_update实现upsert的方案是否正确?
方案正确性说明
你给出的代码是SQLAlchemy ORM场景下实现ON CONFLICT (id) DO UPDATE的标准可行方案,你对「不丢失ORM功能」的判断完全正确。
之前提到的「切换到Core丢失高阶ORM功能」,指的是无法通过session.add(对象) + session.commit()这种纯对象操作的方式实现upsert逻辑,并非只要用到Core语法的语句就完全脱离ORM能力。你的写法保留了ORM的核心优势:
- 直接复用ORM模型
Foo的表、字段映射定义,不需要手动维护表名、字段名字符串,避免了硬编码错误 - 执行后可以通过添加
returning参数直接拿到ORM实例对象,后续可以继续用ORM的方式操作对象,无需额外转换
代码修正点
你当前的代码少了冲突约束的指定逻辑,会导致执行报错,需要补充index_elements参数明确命中id唯一键的冲突规则,修正后的完整代码如下:
class Foo(Base): id = Column(Integer, primary_key=True) bar = Column(Integer) foo = Foo(bar=1) insert_stmt = insert(Foo).values(bar=foo.bar) do_update_stmt = insert_stmt.on_conflict_do_update( # 补充这一行,对应ON CONFLICT (id) index_elements=['id'], set_=dict( bar=insert_stmt.excluded.bar, ) ) session.execute(do_update_stmt) # 记得提交事务 session.commit()
如果需要拿到插入/更新后的ORM对象,可以添加returning逻辑:
do_update_stmt = insert_stmt.on_conflict_do_update( index_elements=['id'], set_=dict( bar=insert_stmt.excluded.bar, ) ).returning(Foo) result = session.execute(do_update_stmt).scalar_one() # 刷新对象确保属性和数据库同步 session.refresh(result)
此时拿到的result就是标准的ORM实例,可以直接调用ORM的相关方法操作。
内容的提问来源于stack exchange,提问作者chaos
相关产品推荐
相关产品推荐

