【AI总结】手把手教你用 Peewee 优雅地「改」数据

手把手教你用 Peewee 优雅地「改」数据


1. 环境准备

pip install peewee

User 模型:

from peewee import *

db = SqliteDatabase('app.db')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    id = AutoField()
    name = CharField()
    age = IntegerField()
    vip = BooleanField(default=False)

2. 单条记录修改的 3 种姿势

2.1 先查后改(最常用)

# 把 id=1 的用户改名为「张三」
user = User.get_by_id(1)
user.name = '张三'
user.save()        # UPDATE user SET name='张三' WHERE id=1;

注意:

  • 只有被修改的字段会生成 UPDATE 语句,Peewee 内部通过 _dirty 集合追踪变化。
  • 如果模型使用了 auto_now=Truesave() 会自动更新时间戳字段。

2.2 链式 update —— 一条 SQL 搞定

n = (User
     .update(name='张三')
     .where(User.id == 1)
     .execute())   # 返回受影响的行数
  • 优点:省去一次 SELECT,适合不需要触发 python 层 @propertypre_save 钩子的场景。
  • 缺点:不会刷新内存对象,不要混用「先查后改」和「链式 update」。

2.3 save() vs update() 对比

场景save()update()
需要触发 pre_save/post_save 钩子
需要即时刷新内存对象
批量更新 10w+ 行❌(N 条 SQL)✅(1 条 SQL)

3. 批量修改的正确姿势

3.1 批量 update —— 一行 SQL 解决

(User
 .update(vip=True)
 .where(User.age >= 18)
 .execute())

3.2 批量 save —— 事务 + 分页

当 update 无法表达业务逻辑(如 python 层加密、日志)时,可用「分页加载 + 批量事务」:

from peewee import chunked

with db.atomic():
    # 每次 100 条,防止一次性加载爆内存
    for user_batch in chunked(User.select().where(User.age < 18), 100):
        for user in user_batch:
            user.vip = False
            user.save()

小技巧:
chunked() 是 Peewee 自带的工具函数,等价于 itertools.islice


4. 原子更新:自增、自减、拼接字段

Peewee 提供了 fn 工具,可以直接在 SQL 层面做原子操作:

from peewee import fn

# age 自增 1
User.update(age=User.age + 1).where(User.id == 1).execute()

# name 末尾拼接「_vip」
User.update(name=fn.CONCAT(User.name, '_vip')).where(User.vip == True).execute()

原子更新可避免并发场景下的「丢失更新」问题。


5. 事务与保存点

with db.atomic() as txn:
    User.update(vip=True).execute()
    # 业务逻辑...
    if some_error:
        txn.rollback()  # 回滚整个事务
    else:
        txn.commit()

小技巧:
使用 db.savepoint() 可以创建嵌套保存点,实现更细粒度回滚。


6. 常见踩坑 & 调试技巧

原因解决方案
save() 不生效未调用 save() 或字段未标记为 dirty修改属性后确保 save()
链式 update 后内存对象未刷新update 不刷新 python 对象重新 get() 或手动赋值
批量更新超时SQLite 默认超时 5sdb = SqliteDatabase('app.db', timeout=20)
更新后外键对象失效外键缓存user.refresh()(Peewee 3.15+ 支持)

调试 SQL:

import logging
logger = logging.getLogger('peewee')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

7. 小结

操作推荐写法
单条更新get() → 改字段 → save()
批量更新update().where().execute()
原子操作update(col=Model.col + 1)
批量 saveatomic() + chunked()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荔枝吻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值