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

Peewee insert_many on_conflict字段保留异常,求正确查询结构

Peewee insert_many on_conflict:保留数据库原有字段,更新其余字段(SQLite)

你之前遇到的问题核心是对preserve参数的理解偏差:这个参数的作用是保留你传入的新数据,而非数据库中已存在的旧数据。如果你需要在冲突发生时,让少数字段保持数据库里的原有值,其余字段用新传入的数据更新,甚至主动更新updated_at这类时间字段,就需要借助SQL标准的EXCLUDED关键字,Peewee对它有很好的支持。

核心概念:EXCLUDED关键字

在SQL的INSERT ... ON CONFLICT语法中,EXCLUDED代表你想要插入的那条“冲突行”的所有数据。Peewee中可以通过字段的.excluded属性(Peewee 3.10及以上版本支持)或者直接用SQL('EXCLUDED.字段名')来引用这些值。

示例1:指定保留数据库字段,手动更新其余字段

假设你需要保留created_at和deleted_at的原有值,更新score、tags、process_at为新传入的数据,同时把updated_at设为当前时间:

from peewee import SQL

# 构建批量插入+冲突处理查询
query = (
    CA.insert_many(data)
    .on_conflict(
        conflict_target=[CA.loc_id],  # 冲突判定字段:loc_id重复时触发
        update={
            # 使用新传入的数据更新字段(引用EXCLUDED)
            CA.score: CA.score.excluded,
            CA.tags: CA.tags.excluded,
            CA.process_at: CA.process_at.excluded,
            # 强制更新updated_at为当前时间(SQLite语法)
            CA.updated_at: SQL('CURRENT_TIMESTAMP'),
            # 保留数据库中的原有值,不做更新
            CA.created_at: CA.created_at,
            CA.deleted_at: CA.deleted_at
        }
    )
).execute()

示例2:批量处理——保留少数字段,其余自动用新数据更新

如果需要保留的字段很少,大部分字段都要更新,不用逐个手动写,可以通过模型元数据批量生成更新规则:

from peewee import SQL

# 定义需要保留数据库原有值的字段
preserve_fields = {CA.created_at, CA.deleted_at}

# 获取模型所有可更新字段(排除主键和要保留的字段)
all_update_fields = [
    field for field in CA._meta.sorted_fields
    if field not in preserve_fields and field != CA.id  # 假设id是主键,无需更新
]

# 生成更新字典:其余字段用新传入的数据
update_dict = {field: field.excluded for field in all_update_fields}
# 额外添加updated_at的自动更新(用本地时间而非UTC)
update_dict[CA.updated_at] = SQL("datetime('now', 'localtime')")

# 执行查询
query = (
    CA.insert_many(data)
    .on_conflict(
        conflict_target=[CA.loc_id],
        update=update_dict
    )
).execute()

关键注意点

  • .excluded属性是Peewee 3.10+才支持的,旧版本可以用SQL('EXCLUDED.字段名')替代,比如CA.score: SQL('EXCLUDED.score')。
  • SQLite的CURRENT_TIMESTAMP返回UTC时间,如果需要本地时间,用datetime('now', 'localtime')。
  • 冲突目标字段conflict_target需要在数据库中有唯一约束(比如UniqueField或者创建表时加的唯一索引),否则ON CONFLICT不会触发。

内容的提问来源于stack exchange,提问作者Liquidgenius

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:45:34