bigywater.tech
Django · 52

migrate 如何选择执行顺序

migrate 是按什么顺序执行迁移的?指定 app 时会多做哪些?回退时谁先撤销?这篇用 --plan 把每种情形的计划直接打出来,再用真实执行验证。

--plan
migrate --plan 打印将要执行的迁移与操作,不真正执行
只补依赖
migrate b 只执行 b 依赖的迁移和 b 自己,不多做
反向依赖
回退 a 到 zero 时,先撤销依赖 a 的 b.0001

全新数据库的计划

实测 · 本机执行输出
   Planned operations:
   a.0001_initial
   Create model A
   a.0002_a_z
   Add field z to a
   b.0001_initial
   Create model B
   c.0001_initial
   Create model C
   c.0002_c_w
   Add field w to c
   contenttypes.0001_initial
   Create model ContentType
   Alter unique_together for contenttype (1 constraint(s))
   contenttypes.0002_remove_content_type_name
   Change Meta options on contenttype
   Alter field name on contenttype
   Raw Python operation
   Remove field name from contenttype

计划顺序不是「按 app 分组」也不是「按编号排序」,只保证依赖先于被依赖者。不要依赖计划里没有依赖声明的顺序。

指定 app 与目标

实测 · 本机执行输出
  migrate b --plan:
    Planned operations:
    a.0001_initial
    Create model A
    b.0001_initial
    Create model B
  migrate a 0001 --plan:
    Planned operations:
    a.0001_initial
    Create model A

migrate <app> <name> 是「迁移到这个点」:补齐依赖并停在这里;如果目标在当前状态之前,就是回退。

执行记录

实测 · 本机执行输出
  ('a', '0001_initial')
  ('a', '0002_a_z')
  ('b', '0001_initial')
  ('c', '0001_initial')
  ('c', '0002_c_w')
  ('contenttypes', '0001_initial')
  ('contenttypes', '0002_remove_content_type_name')

记录的顺序就是实际执行的顺序(id 递增)。

回退

实测 · 本机执行输出
  migrate a 0001 --plan(现在库里全部已应用):
    Planned operations:
    a.0002_a_z
    Undo Add field z to a
  migrate a zero --plan:
    Planned operations:
    b.0001_initial
    Undo Create model B
    a.0002_a_z
    Undo Add field z to a
    a.0001_initial
    Undo Create model A

回退计划同样由图决定:要撤销的迁移的「依赖者」必须先被撤销。

run_before

实测 · 本机执行输出
   [X]  c.0001_initial
   [X]  a.0001_initial
   [X]  a.0002_a_z
   [X]  b.0001_initial
   [X]  c.0002_c_w
   [X]  contenttypes.0001_initial
   [X]  contenttypes.0002_remove_content_type_name

本实验里我只验证了 showmigrations --plan 里的顺序变了,没有真正在会因顺序出错的场景里验证。

分步演示:迁移的执行顺序

migrate 执行顺序
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。SQLite;三个 app,a / c 各两个迁移,b 依赖 a.0001
    • 没有验证:swappable_dependency、跨 app 的循环依赖拆分、--plan 在 PostgreSQL 上的输出与 SQLite 是否一致、大量迁移下 migrate 的加载耗时
    京ICP备2026067502号-1京公网安备11010502063487号