2.3 迁移机制与结构演进


文档摘要

2.3 迁移机制与结构演进 本节摘要:迁移系统是 Django 管理表结构演进的机制:把模型改动写成版本化的迁移脚本,再按序应用到数据库。本节讲迁移的生成与审查流程、迁移状态表的作用、以及模型改动后"两步走"的纪律。数据库结构是项目里最难回滚的东西,迁移系统的全部设计都围绕"可审查、可重放、可回退"。 两步走:生成与应用 迁移的工作流永远是两条命令: 第一步只写文件不动数据库,第二步只动数据库不改文件。分开的意义在于审查:生成的脚本先看一眼再应用,是保护生产库的最后防线。想看它到底会执行什么 SQL: 输出类似这样(以 PostgreSQL 为例的节选): 每条迁移都有编号与依赖链,框架靠一张自动维护的状态表(djangomigrations)记录"哪些迁移已经应用"。

2.3 迁移机制与结构演进

本节摘要:迁移系统是 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 章的夹具重建。这个自由在生产环境不存在。生产上的三条纪律:

  1. 迁移随代码一起部署,发布脚本里固定执行 migrate,绝不依赖"某人记得去跑"。
  2. 破坏性操作先演练:删列、改列类型在满数据的表上可能锁表数分钟,sqlmigrate 预览加上预发环境试跑是最低要求。
  3. 不修改已应用的历史迁移。改了,状态表记录与实际结构就对不上,后患无穷。改错了就再生成一个新迁移纠正。

墨迹博客的第一次迁移很快就生成:四张业务表加中间表,一次性建齐。从这一章起,"模型改动必须配一个迁移"成为肌肉记忆,项目生命周期的数据库线正式开动。

迁移文件的历史价值

迁移脚本还有一层常被低估的身份:它是数据库结构的编年史。每个迁移文件记录着一次结构决策的动机与时间,文件名里的序号串起来就是表结构从第一版到当前的完整演化路径。墨迹博客维护一年后回看迁移目录,能看到产品需求如何在数据层留下痕迹——加软删除字段那次对应回收站需求,拆评论表那次对应支持楼层回复。这层价值决定了两条纪律:迁移文件一旦提交进版本库就绝不修改历史文件,哪怕它有明显瑕疵,也用新迁移去修正——改写历史会让其他环境的应用顺序错乱;提交信息要写清楚为什么改,而不只是改了什么。将来接手的人排查数据问题时,最先翻的就是这份编年史。

本节要点回顾

  • 两步纪律:makemigrations 只写文件、migrate 只动数据库,中间夹一道 sqlmigrate 审查。
  • 状态表驱动:迁移是否应用由数据库里的记录说了算,环境间靠重放迁移对齐结构。
  • 数据迁移用 RunPython:存量数据整形进版本化脚本,拒绝手工临时操作。
  • 生产三律:迁移随部署走、破坏性操作先演练、历史迁移只增不改。

表结构就绪。下一章进入 ORM 查询的世界,让这些表真正开始干活。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U