Django4.0 迁移-压缩迁移
我们鼓励你自由地进行迁移,而不要担心你有多少迁移;迁移代码经过优化,可以一次处理几百个迁移,而不会有太多的减速。然而,最终你会希望从几百个迁移回归到只有几个,这就是压缩的作用。
压缩是将一组现有的多个迁移减少到一个(有时是几个)迁移,这些迁移仍然代表相同的更改。
Django通过获取所有现有迁移,提取它们的 Operation
并将它们按顺序排列,然后对它们运行一个优化器,以尝试减少列表的长度——例如,它知道 CreateModel
和 DeleteModel
相互抵消,它还知道 AddField
可以卷入 CreateModel
。
一旦操作序列被尽可能地减少——可能的数量取决于你的模型有多紧密交织,如果你有任何 RunSQL 或 RunPython 操作(除非它们被标记为 elidable
,否则无法被优化),Django就会把它写回一组新的迁移文件中。
这些文件被标记为替换了先前压缩的迁移,因此它们可以与旧迁移文件共存,Django 将根据你在历史记录中的位置智能地在它们之间切换。如果你仍处于压缩过程中,则它将继续使用它们直到结束,然后切换到压缩历史记录,而新安装将使用新压缩后的迁移并跳过所有旧迁移。
这样你就可以压缩而不至于把目前还没有完全更新的生产系统搞乱。推荐的流程是压缩,保留旧文件,提交并发布,等到所有系统都升级到新版本(或者如果你是第三方项目,确保你的用户按顺序升级版本,不跳过任何一个版本),然后删除旧文件,提交并进行第二次发布。
支持这一切的命令是 squashmigrations
——把你想压缩的应用标签和迁移名称传给它,它就会开始工作:
$ ./manage.py squashmigrations myapp 0004
Will squash the following migrations:
- 0001_initial
- 0002_some_change
- 0003_another_change
- 0004_undo_something
Do you wish to proceed? [yN] y
Optimizing...
Optimized from 12 operations to 7 operations.
Created new squashed migration /home/andrew/Programs/DjangoTest/test/migrations/0001_squashed_0004_undo_something.py
You should commit this migration but leave the old ones in place;
the new migration will be used for new installs. Once you are sure
all instances of the codebase have applied the migrations you squashed,
you can delete them.
如果要设置压缩迁移的名称而不是使用自动生成的迁移名称,请使用 squashmigrations --squashed-name
选项。
请注意,Django 中的模型相互依赖可能会变得非常复杂,压缩可能会导致迁移无法运行;要么是优化错误(在这种情况下,你可以用 --no-optimize
再试一次,不过你也应该报告这个问题),要么是 CircularDependencyError
,在这种情况下,你可以手动解决它。
要手动解决 CircularDependencyError
问题,请将循环依赖中的外键分离到单独的迁移中,并将依赖项移到另一个应用上。如果你不确定,请参见 makemigrations
在被要求从模型创建全新的迁移时如何处理问题。在未来的 Django 版本中,squashmigrations
将被更新以尝试自己解决这些错误。
一旦你压缩了你的迁移,你应该把它和它所替代的迁移一起提交,并把这个更改分发到你的应用程序的所有运行中的实例,确保它们运行 migrate
来将更改存储在它们的数据库中。
然后,你必须通过以下方法将压缩的迁移过渡到正常迁移:
- 删除它替换的所有迁移文件。
- 将所有依赖被删除迁移的迁移更新为依赖被压缩的迁移。
- 删除压缩迁移的
Migration
类的 replaces
属性(这就是 Django 告诉它是压缩迁移的方式)。
压缩迁移后,在完全将其转换为正常迁移之前,你不应该再重新压缩该压缩的迁移。