直接用sqlitedatabase('path.db')实例化即可自动建库,路径为相对工作目录;需调用create_tables()建表,否则报“no such table”;推荐用绝对路径或':memory:'测试;多线程勿共用同一database实例。

怎样用peewee连接并初始化SQLite数据库
直接用SqliteDatabase实例化即可,路径传字符串就行,不需要预先创建文件——SQLite会在第一次写入时自动建库。注意路径是相对当前工作目录的,不是脚本所在目录,容易因运行位置不同导致“找不到表”这类问题。
常见错误现象:OperationalError: no such table,往往是因为数据库路径不对,或者模型没调.create_tables()。
- 推荐显式指定绝对路径,比如
os.path.join(os.path.dirname(__file__), 'app.db') - 如果只是临时测试,用
:memory:(如SqliteDatabase(':memory:'))可避免文件残留 - 别在多个线程里共用同一个
Database对象,SQLite默认不支持多线程并发写入
定义模型时怎么对应SQLite的数据类型和约束
Peewee的字段类基本能映射到SQLite原生类型,但SQLite本身弱类型,所以重点不在类型声明,而在约束和索引是否生效。比如CharField(max_length=100)不会限制长度(SQLite不校验),但加unique=True或index=True会真实生成对应DDL。
使用场景:需要全文搜索?得手动加FTSModel子类;想用自增主键但又不想叫id?得显式设primary_key=True并禁用默认id字段。
-
IntegerField→ SQLite 的INTEGER,主键自动带AUTOINCREMENT(仅当声明为PrimaryKeyField或AutoField) -
TextField和CharField都映射为TEXT,无实际长度区别 - 外键约束默认不启用,需在
Database初始化时加参数pragmas={'foreign_keys': 1}
执行查询时为什么.get()报DoesNotExist而.select().first()返回None
这是Peewee最常踩的坑:异常 vs 空值语义不同。.get()预期“一定存在”,查不到就抛DoesNotExist子类异常(比如User.DoesNotExist);.select().first()是安全兜底方式,查不到就安静返回None。
性能影响:两者底层都是SELECT ... LIMIT 1,性能无差别,选哪个纯看错误处理风格。
- 适合用
.get()的场景:用户登录时根据username查账号,查不到就该报错 - 适合用
.select().first()的场景:根据URL slug查文章,查不到就渲染404页面 - 别对可能为空的字段(如
user.profile)直接链式调用.get(),先判空或用.select().join(...).switch()改写关联查询
批量插入数据为什么慢?怎么用insert_many()提速
默认逐条.save()会为每条记录开事务、编译SQL、执行,IO开销大。SQLite在单事务内插入比多事务快一个数量级。
参数差异:insert_many()接受字典列表或元组列表,不走模型实例化流程,绕过验证和钩子(如save()里的pre_save),所以更快但也更“裸”。
- 必须保证字段顺序和
fields参数一致,否则数据错位(比如insert_many([{'name': 'a', 'age': 10}], fields=[User.age, User.name])会导致name进age列) - 如果要触发模型钩子,还是得用
Model.create()循环,或自己手动调pre_save - 超过500行建议分批,SQLite单语句有参数上限(通常999),用
chunk_size=100参数控制
SQLite的ACID特性在默认配置下依赖于磁盘刷写,如果关掉synchronous=OFF能快几倍,但断电可能丢数据——开发阶段可调,生产环境慎动。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











