peewee调用bulk_update无报错但MySQL未更新任何记录的问题
问题根因
代码里有两个写法问题直接导致更新失效,没有报错是因为逻辑本身没有语法或数据库连接错误,只是最终生成的SQL没有命中任何待更新行:
- 漏查主键字段:peewee的
bulk_update默认靠模型主键匹配要更新的数据库行,生成的UPDATE语句WHERE条件会携带主键值定位记录。你写的select只查了word、queried、updated三个字段,如果模型主键是默认的自增id字段,返回的模型实例里没有主键值,peewee拿不到匹配条件,自然更新不到任何记录。 - 没有把查询结果转成实体列表:
Word.select()返回的是懒加载查询对象,不是已经读到内存里的固定结果集。你第一次循环遍历改完属性后,不管是后面的debug打印循环,还是传给bulk_update时的内部遍历,只要再次迭代这个查询对象,都会重新向数据库发起查询,拿到的全是没改过的原始数据,之前的修改全落在了用完就丢的临时实例上,根本没传到bulk_update的执行逻辑里。
额外说明:你给bulk_update传的fields里包含Word.word,但整个逻辑从来没修改过word字段的值,多余的字段只会让生成的SQL多做无用判断,没有实际意义。
修复方法
对照三点调整即可:
- 查询时必须把主键字段加到select的字段列表里,嫌裁剪字段麻烦直接用
Word.select()查全字段也可以 - 查询结果直接套
list()转成内存列表,把懒加载的查询物化,避免后续重复触发数据库查询 - bulk_update的fields参数只传你实际修改过的字段,也就是
queried和updated就够了
修复后可运行代码
from datetime import datetime # 查询时带上主键,直接转列表固定内存结果 words = list( Word.select(Word.id, Word.word, Word.queried, Word.updated) .where(Word.word << result_words) ) # 遍历修改内存中实例的属性 for word in words: word.queried += 1 word.updated = datetime.now() # 这里打印的就是修改后的值,不会触发重复查库 for word in words: print(word.word, word.queried, word.updated) batch_size = 50 with db.database.atomic(): # 只传入实际修改的字段 Word.bulk_update( words, fields=[Word.queried, Word.updated], batch_size=batch_size )
内容的提问来源于stack exchange,提问作者SimonB
相关产品推荐
相关产品推荐

