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
相关产品推荐
相关产品推荐

