将“on_conflict_do_update()”与 sqlalchemy ORM 结合使用

cha*_*aos 6 python sqlalchemy

我目前正在使用 SQLAlchemy ORM 来处理我的数据库操作。现在我有一个需要ON CONFLICT (id) DO UPDATE. 该方法on_conflict_do_update()似乎是正确的使用方法。但这里的帖子说代码必须切换到 SQLAlchemy 核心,并且缺少高级 ORM 功能。我对这个说法感到困惑,因为我认为像下面的演示这样的代码可以实现我想要的,同时保留 SQLAlchemy ORM 的功能。

class Foo(Base):
  ...
  bar = Column(Integer)


foo = Foo(bar=1)


insert_stmt = insert(Foo).values(bar=foo.bar)
do_update_stmt = insert_stmt.on_conflict_do_update(
    set_=dict(
        bar=insert_stmt.excluded.bar,
    )
)

session.execute(do_update_stmt)
Run Code Online (Sandbox Code Playgroud)

我还没有在我的项目上测试它,因为它需要大量的修改。请问这是否是处理ON CONFLICT (id) DO UPDATESQLALchemy ORM 的正确方法?

Gor*_*son 4

正如文档中所述,constraint=参数是

表上的唯一或排除约束的名称,或者约束对象本身(如果它具有 .name 属性)。

所以我们需要将 PK 约束的名称传递给.on_conflict_do_update().

我们可以通过检查接口获取PK约束名称:

insp = inspect(engine)
pk_constraint_name = insp.get_pk_constraint(Foo.__tablename__)["name"]
print(pk_constraint_name)  # tbl_foo_pkey

new_bar = 123
insert_stmt = insert(Foo).values(id=12345, bar=new_bar)
do_update_stmt = insert_stmt.on_conflict_do_update(
    constraint=pk_constraint_name, set_=dict(bar=new_bar)
)

with Session(engine) as session, session.begin():
    session.execute(do_update_stmt)
Run Code Online (Sandbox Code Playgroud)