Peewee ORM 查询操作详解:从基础CRUD到高级批量处理
概述
Peewee 是一个轻量级 Python ORM(对象关系映射)工具,提供了简洁而强大的数据库操作接口。本文将深入讲解 Peewee 中的查询操作,涵盖从基础的 CRUD(创建、读取、更新、删除)到高级的批量处理技巧。
创建记录
基本创建方法
Peewee 提供了多种创建记录的方式:
# 方法1:使用create()直接创建
user = User.create(username='Charlie')
# 方法2:先实例化再保存
user = User(username='Charlie')
user.save() # 返回受影响的行数
# 方法3:使用insert()不创建模型实例
user_id = User.insert(username='Charlie').execute()
外键关联创建
处理外键关系时,可以直接传递模型实例:
tweet = Tweet.create(user=user, message='Hello!')
# 等价于
tweet = Tweet.create(user=user.id, message='Hello!')
批量插入
对于大量数据插入,Peewee 提供了多种优化方案。
基础批量插入
data = [{'username': 'user1'}, {'username': 'user2'}]
# 方法1:循环+事务
with db.atomic():
for item in data:
User.create(**item)
高效批量插入
使用 insert_many()
可以显著提高性能:
# 使用字典列表
User.insert_many(data).execute()
# 使用元组列表(需指定字段)
users = [('user1',), ('user2',)]
User.insert_many(users, fields=[User.username]).execute()
分批次插入
对于超大数据集,建议分批次处理:
from peewee import chunked
with db.atomic():
for batch in chunked(data, 100): # 每批100条
User.insert_many(batch).execute()
替代方案
bulk_create()
方法可以直接插入未保存的模型实例:
users = [User(username='user%s' % i) for i in range(1000)]
with db.atomic():
User.bulk_create(users, batch_size=100)
更新记录
单个记录更新
保存已有主键的记录会自动转为更新操作:
user = User.get(User.username == 'Charlie')
user.username = 'Charles'
user.save() # 执行UPDATE操作
批量更新
# 更新所有创建于今天的推文
today = datetime.today()
query = Tweet.update(is_published=True).where(Tweet.creation_date < today)
updated_count = query.execute()
原子更新
避免竞态条件的原子更新:
# 不安全方式(有竞态条件风险)
stat = Stat.get(Stat.url == request.url)
stat.counter += 1
stat.save()
# 安全方式(原子操作)
query = Stat.update(counter=Stat.counter + 1).where(Stat.url == request.url)
query.execute()
高级更新示例
# 给所有员工加10%薪水的奖金
Employee.update(bonus=(Employee.bonus + (Employee.salary * .1))).execute()
# 使用子查询更新用户推文数
subquery = Tweet.select(fn.COUNT(Tweet.id)).where(Tweet.user == User.id)
User.update(num_tweets=subquery).execute()
更新或插入(Upsert)
替换式Upsert
# 如果用户存在则替换,不存在则插入
User.replace(username='the-user', last_login=datetime.now()).execute()
# 等价于
User.insert(username='the-user', last_login=datetime.now()).on_conflict_replace().execute()
MySQL风格Upsert
User.insert(username='huey', login_count=1).on_conflict(
preserve=[User.last_login], # 保留插入值
update={User.login_count: User.login_count + 1} # 递增计数
).execute()
PostgreSQL/SQLite风格Upsert
User.insert(username='huey', last_login=now, login_count=1).on_conflict(
conflict_target=[User.username], # 冲突目标
preserve=[User.last_login],
update={User.login_count: User.login_count + 1}
).execute()
高级Upsert示例
# 仅当新值大于原值时更新
query = (KV.insert(key='k1', value=10)
.on_conflict(
conflict_target=[KV.key],
update={KV.value: KV.value + EXCLUDED.value},
where=(EXCLUDED.value > KV.value)))
query.execute()
总结
Peewee 提供了丰富而灵活的数据库操作接口,从简单的单记录操作到复杂的批量处理都能高效完成。关键点包括:
- 批量操作时务必使用事务
- 优先选择
insert_many()
和bulk_create()
进行大批量插入 - 更新操作使用原子方式避免竞态条件
- 根据数据库类型选择合适的 Upsert 策略
掌握这些技巧可以显著提高数据库操作效率,特别是在处理大量数据时。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考