在 Django 的迁移代码中,有一个 squashmigrations
命令:“如果可能,将 app_label
的迁移压缩到并包括 migration_name
到更少的迁移中。”
因此,如果您想压缩前 5 次迁移,这将有所帮助。
从特定的 migration_name
开始压缩的最佳方法是什么?
在我目前正在进行的一个项目中,我们添加了 5-10 个新的迁移文件,因为我们添加了新功能。我们将立即部署整个项目,看起来单独运行这些项目将花费太长时间。我想将这个项目的所有迁移压缩成一个迁移并测试运行它的时间。
sqlmigrate
查看将运行的 SQL,并将四个单独的 ALTER TABLE 语句组合成一个具有四个 ADD COLUMN 部分的语句,并使用带有 state_operations
参数的 migrations.RunSQL
运行它,以保持迁移状态逻辑满意。
python manage.py squashmigrations <appname> <squashfrom> <squashto>
python manage.py help squashmigrations
https://docs.djangoproject.com/en/dev/topics/migrations/#migration-squashing
这将使您能够更精细地控制要压缩的迁移,并让您保持更清晰的提交历史记录。删除 + 重新创建所有迁移可能会导致其他问题,例如循环依赖,具体取决于模型的构建方式。
您可以删除迁移文件并再次运行 makemigrations
。如果您有使用这些的开发部署,您应该 migrate back 到您删除的第一个之前的那个。
此外,最好先提交代码,以防出现问题。
还:
稍微复杂的是,如果有自定义 RunPython 代码,它将不会包含在 makemigrations 创建的新迁移中
RunPython
代码,它将不会包含在 makemigrations
创建的新迁移中
__init__
之后的所有迁移),然后运行 makemigrations
并看到类似 You have 1 unapplied migration(s)
的消息,您可以运行 ./manage.py migrate --fake
来“伪造”迁移(尽管其他团队成员将获得完整移民)。
RunPython
、您的开发团队成员等。感谢您在混乱中指出显而易见的事情。
我创建 django-squash
https://pypi.org/project/django-squash/ 是为了不必在每个应用级别或更糟的每个应用特定迁移级别上处理迁移,而是在每个项目级别上处理它。这个想法是希望在某个时候将它集成到核心 Django 中。
基本思路:
你有一个产品,没有其他人可以增强的开源,但是你的,你的团队,你来处理它。
在每个版本之后,您都希望压缩您在过去版本中所做的所有迁移并开始一个新版本,因为您的产品已经从上一个版本和您的数据模型演变而来。
你 squash,它会查看你之前是否已经 squash,如果有,它会删除所有在你的代码库中没有业务的非常旧的迁移。最后,为您的迁移创建一个新快照,并保留您现有的迁移。
您将在每个版本/当您觉得您的测试在运行所有迁移时花费太长时间时执行此操作。
例子:
/app1/migrations/__init__.py
/app1/migrations/0001_initial.py
/app1/migrations/0002_created_user_model.py
/app1/migrations/0003_added_username.py
/app1/migrations/0004_added_password.py
/app1/migrations/0005_last_name.py
你已经全部应用了。
但是每次运行测试时,这些步骤中的每一个都需要运行,这会花费宝贵的时间。所以我们压扁。新目录将如下所示:
/app1/migrations/__init__.py
/app1/migrations/0001_initial.py
/app1/migrations/0002_created_user_model.py
/app1/migrations/0003_added_username.py
/app1/migrations/0004_added_password.py
/app1/migrations/0005_last_name.py
/app1/migrations/0006_squash.py
在 0006_squash.py
内,您会发现一个带有迁移 1-5 名称的 replaces = [..]
。如果您删除所有迁移并使用 elidable=False
执行 ./manage.py makemigrations
+ any RunSQL
/RunPython
,您还会发现 Migration.operations = [..]
包含您所期望的所有内容。如果您部署到缺少任何迁移 1-5 的环境,它将从源应用它而不使用 0006。 (这是标准的 Django 迁移)
一段时间过去了,现在您的迁移看起来像这样:
/app1/migrations/__init__.py
/app1/migrations/0001_initial.py
/app1/migrations/0002_created_user_model.py
/app1/migrations/0003_added_username.py
/app1/migrations/0004_added_password.py
/app1/migrations/0005_last_name.py
/app1/migrations/0006_squash.py
/app1/migrations/0007_change_username_to_100_char.py
/app1/migrations/0008_added_dob.py
你又压扁了。这次会发生以下情况。 replaces = [..]
中的所有内容都将被删除。 0006_squash.py
将被修改为使 replaces
为空列表。最后,将使用新的更改重新创建壁球。总而言之,将如下所示:
/app1/migrations/0006_squash.py
/app1/migrations/0007_change_username_to_100_char.py
/app1/migrations/0008_added_dob.py
/app1/migrations/0009_squash.py
再次开始循环。
Django 1.9 中引入了 Squash 迁移命令
如果您使用的是 Django 1.8,则需要
从 Django 1.9 版本 https://github.com/django/django/blob/stable/1.9.x/django/core/management/commands/squashmigrations.py 获取 squashmigrations.py
将它放在你的项目中,在 /-package-/-app-/management/commands/ 下
重命名为 squashmigrations19.py
运行 ./manage.py squashmigrations19 -app- 0002 0003
manage.py squashmigrations myapp 0011 0015
将迁移 0011_auto_someintshere 压缩到 0015_auto_someintshere