2.3 迁移机制与结构演进 本节摘要:迁移系统是 Django 管理表结构演进的机制:把模型改动写成版本化的迁移脚本,再按序应用到数据库。本节讲迁移的生成与审查流程、迁移状态表的作用、以及模型改动后"两步走"的纪律。数据库结构是项目里最难回滚的东西,迁移系统的全部设计都围绕"可审查、可重放、可回退"。 两步走:生成与应用 迁移的工作流永远是两条命令: 第一步只写文件不动数据库,第二步只动数据库不改文件。分开的意义在于审查:生成的脚本先看一眼再应用,是保护生产库的最后防线。想看它到底会执行什么 SQL: 输出类似这样(以 PostgreSQL 为例的节选): 每条迁移都有编号与依赖链,框架靠一张自动维护的状态表(djangomigrations)记录"哪些迁移已经应用"。
本节摘要:迁移系统是 Django 管理表结构演进的机制:把模型改动写成版本化的迁移脚本,再按序应用到数据库。本节讲迁移的生成与审查流程、迁移状态表的作用、以及模型改动后"两步走"的纪律。数据库结构是项目里最难回滚的东西,迁移系统的全部设计都围绕"可审查、可重放、可回退"。
迁移的工作流永远是两条命令:
# 第一步:对比模型与上一次迁移的差异,生成迁移脚本 python manage.py makemigrations blog # 第二步:把尚未应用的迁移按顺序执行到数据库 python manage.py migrate
第一步只写文件不动数据库,第二步只动数据库不改文件。分开的意义在于审查:生成的脚本先看一眼再应用,是保护生产库的最后防线。想看它到底会执行什么 SQL:
python manage.py sqlmigrate blog 0001
输出类似这样(以 PostgreSQL 为例的节选):
BEGIN; CREATE TABLE "blog_article" ( "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "title" varchar(200) NOT NULL, "body" text NOT NULL, "status" smallint NOT NULL, "created_at" timestamp with time zone NOT NULL ); COMMIT;
每条迁移都有编号与依赖链,框架靠一张自动维护的状态表(django_migrations)记录"哪些迁移已经应用"。换一台机器、一个环境,跑一次 migrate 就能把表结构同步到位——这正是第 10 章部署流程里"发布时执行迁移"的底气。

迁移不只管结构,也管数据整形。典型场景:给已有表加一个非空字段。直接加,老行的该列没有值,数据库会拒绝。规范做法是"加默认值、迁数据、收紧约束"三步,或写一个数据迁移:
# 数据迁移示例:为存量文章回填阅读计数 from django.db import migrations def backfill_views(app_registry, schema_editor): Article = app_registry.get_model("blog", "Article") Article.objects.update(view_count=0) class Migration(migrations.Migration): dependencies = [("blog", "0006_add_view_count")] operations = [ migrations.RunPython(backfill_views, migrations.RunPython.noop), ]
RunPython 接收正反两个函数:正向回填,反向空操作(回填过的数据不必撤销)。凡是"上线时要把存量数据挪个位置"的需求,都用数据迁移解决,别在服务器上手工跑临时脚本——迁移会被记录状态、可重复、可审查,手工操作三者皆无。
⚠️ 最常见的翻车现场:同事各自生成了编号相同的不同迁移,合并代码后 migrate 报"依赖冲突"。解法是用 merge 参数让框架合并依赖,平时约定"改完模型立刻生成迁移并提交",冲突自然减少。
开发阶段数据库随时可推倒:删库文件重新 migrate,测试数据用第 9 章的夹具重建。这个自由在生产环境不存在。生产上的三条纪律:
墨迹博客的第一次迁移很快就生成:四张业务表加中间表,一次性建齐。从这一章起,"模型改动必须配一个迁移"成为肌肉记忆,项目生命周期的数据库线正式开动。
迁移脚本还有一层常被低估的身份:它是数据库结构的编年史。每个迁移文件记录着一次结构决策的动机与时间,文件名里的序号串起来就是表结构从第一版到当前的完整演化路径。墨迹博客维护一年后回看迁移目录,能看到产品需求如何在数据层留下痕迹——加软删除字段那次对应回收站需求,拆评论表那次对应支持楼层回复。这层价值决定了两条纪律:迁移文件一旦提交进版本库就绝不修改历史文件,哪怕它有明显瑕疵,也用新迁移去修正——改写历史会让其他环境的应用顺序错乱;提交信息要写清楚为什么改,而不只是改了什么。将来接手的人排查数据问题时,最先翻的就是这份编年史。
表结构就绪。下一章进入 ORM 查询的世界,让这些表真正开始干活。