
peewee 的 modelselect 查询对象本身不可直接序列化(如存入 redis),因其包含动态数据库上下文和游标引用;正确做法是执行查询获取模型实例后,再用 model_to_dict() 序列化为字典,必要时通过 dict_to_model() 还原为模型实例。
在 Telegram 机器人等无状态服务中,常需持久化分页查询逻辑(如翻页键盘对应的查询条件)。但直接尝试序列化 ModelSelect 对象(如 User.select().where(User.id == 1))会失败——它并非数据容器,而是查询构建器 + 执行代理,内部持有数据库连接、SQL 编译状态及未执行的游标引用,无法被 JSON 或 pickle 安全序列化。
✅ 正确路径:先执行,再序列化数据
只需调用 .get()(单条)、.first() 或 .execute() + 列表推导(多条),获得实际的模型实例,再转换为字典:
from playhouse.shortcuts import model_to_dict, dict_to_model
from peewee import *
# 假设已定义 User 模型与数据库
item = User.select().where(User.id == 1).get() # ← 关键:执行查询,返回 User 实例
data_dict = model_to_dict(item) # ✅ 成功:{'id': 1, 'name': 'new_user'}
# 存入 Redis(示例)
import redis
r = redis.Redis()
r.set('user:1', json.dumps(data_dict)) # 可安全存储
# 从 Redis 加载并还原为模型实例
stored = json.loads(r.get('user:1'))
restored_user = dict_to_model(User, stored) # ✅ 返回 User 实例,可调用 .save() 等方法
print(restored_user.name) # 输出: new_user⚠️ 注意事项:
- model_to_dict() 默认只序列化字段值,不包含外键关联对象(除非显式传入 recurse=True);若需关联数据,请手动处理或使用 model_to_dict(model, recurse=True, backrefs=True)。
- dict_to_model() 仅重建模型实例的属性,不会自动关联数据库状态——还原后的实例是“游离态”(detached),若需更新数据库,须显式调用 .save() 或绑定到事务。
- 若需保存查询逻辑本身(如分页参数、过滤条件),建议分离关注点:将 where 条件、order_by、paginate 页码等元信息单独结构化存储(如 { "model": "User", "filters": {"id__gt": 10}, "page": 2 }),运行时动态重建 ModelSelect,而非试图序列化查询对象。
总结:Peewee 查询对象不是数据载体,而是执行指令集。持久化应聚焦于结果数据或查询参数,而非查询对象本身——这是理解 ORM 序列化边界的关键原则。










