知其然,知其所以然
Django 2026-09-30

Django 分页为什么会触发 COUNT(*)

在 100 万行的 PostgreSQL 表上量 Django 分页:Paginator 先发 COUNT(*)(14.1 ms)再发 LIMIT/OFFSET;第 1 页 0.26 ms,最后一页 42.5 ms(OFFSET 越深越慢);keyset 只要 0.32 ms;未排序会警告。

Django 分页 Paginator COUNT PostgreSQL 真实验证 动画演示
Django 2026-09-30

Django Migration 文件与依赖图

三个 app(people ← orders ← billing)实测迁移文件与依赖图:外键决定跨 app 依赖、同 app 后一个依赖前一个;showmigrations --plan 是拓扑排序后的计划;django_migrations 只记录已应用的迁移;MigrationLoader 的节点与叶子;循环依赖抛 CircularDependencyError。

Django Migration 依赖图 真实验证 动画演示
Django 2026-09-30

makemigrations 如何检测模型变化

逐项改动模型,看 makemigrations 检测到什么、sqlmigrate 有多少条 SQL:新增字段需要默认值或 NULL;help_text / choices 会生成 0 条 SQL 的迁移;字段改名在 --noinput 下被当作删除 + 新增;改名同时改类型永远是删除 + 新增;纯 Python 方法不产生迁移。

Django Migration makemigrations 真实验证 动画演示
Django 2026-09-30

migrate 如何选择执行顺序

用三个互相依赖的 app 实测 migrate 的执行顺序:migrate --plan 是依赖 + 图遍历的结果;只迁移某个 app 时只补齐依赖;回退按反向依赖(先撤销依赖者);django_migrations 只存已应用记录;run_before 能让别的 app 的迁移排到自己后面。

Django Migration 执行顺序 真实验证 动画演示
Django 2026-09-30

RunPython 数据迁移

实测 RunPython 数据迁移:apps.get_model 拿到的是没有自定义方法的历史模型;10 万行回填,一条 UPDATE(F / Concat)1.55 s,Python 循环 + bulk_update 2 万行就要 1.55 s;迁移里 import 真实模型会在全新库上因列不存在而失败。

Django Migration RunPython 数据迁移 PostgreSQL 真实验证 动画演示
Django 2026-09-30

数据迁移中的正向与反向操作

实测迁移的正向与反向:RunPython 没有 reverse_code 时回退抛 IrreversibleError,加 RunPython.noop 才能回退;noop 反向不还原数据;RemoveField 回退只恢复列不恢复数据(值变成 default);DeleteModel 回退得到空表。

Django Migration 可逆迁移 真实验证 动画演示
Django 2026-09-30

Migration 执行失败后的恢复方式

在 PostgreSQL 上让迁移的第二条操作失败:默认 atomic 时整个迁移回滚,库里无残留;atomic = False 时第一条已提交而迁移没有记录(半应用),再次 migrate 会因列已存在而失败;恢复的办法是让实际状态与 django_migrations 记录重新一致,或用 --fake。

Django Migration 失败恢复 PostgreSQL 真实验证 动画演示
Django 2026-09-30

--fake 与 --fake-initial

实测 --fake 与 --fake-initial:库里已有同名表时直接 migrate 报 relation already exists;--fake-initial 检查表存在就只记录;但它不核对列,少一列也 FAKED,之后写入才失败;--fake 只写记录不碰表,回退同样只删记录。

Django Migration fake fake-initial PostgreSQL 真实验证 动画演示
Django 2026-09-30

Migration 冲突与合并

两个分支各生成一个依赖 0001 的迁移时 migrate / makemigrations 都拒绝工作;makemigrations --merge 生成空操作的合并迁移;合并不检查两个分支是否兼容——同一字段加不同类型,SQLite 悄悄改成后者,PostgreSQL 直接报错。

Django Migration 冲突 merge 真实验证 动画演示
Django 2026-09-30

Migration Squashing

实测 squashmigrations:5 个迁移优化成 1 个操作(SQL 17 → 1 条);新旧迁移共存时,全新数据库走合并迁移,部分应用的数据库继续走旧迁移;replaces 声明它替代的迁移。

Django Migration squashmigrations 真实验证 动画演示
Django 2026-09-30

大表结构迁移的风险

在 200 万行的 PostgreSQL 表上,一边每 5 ms 写一行一边跑迁移:加列几乎不阻塞(1 ms);integer → bigint 重写整表阻塞写入 1220 ms;改 NOT NULL 286 ms;普通建索引 587 ms,CONCURRENTLY 只有 1 ms。

Django Migration 大表 锁 PostgreSQL 真实验证 动画演示
Django 2026-09-30

字段默认值为什么可能锁表

200 万行 PostgreSQL 表上给字段加默认值:常量默认值 0.25 s 且 Django 会 DROP DEFAULT;callable default(uuid4)整表拿到同一个值(1 个不同值);db_default 保留数据库默认值;volatile 函数默认值 1.52 s(重写整表);null → 分批回填 → NOT NULL 的三步法。

Django Migration 默认值 大表 PostgreSQL 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号