【问题标题】:How to squash recent Django migrations?如何压缩最近的 Django 迁移?
【发布时间】:2017-02-23 00:36:36
【问题描述】:

在 Django 的迁移代码中,有一个 squashmigrations 命令:“如果可能,将app_label 的迁移压缩到包括migration_name 在内的更少迁移。”

因此,如果您想压缩前 5 次迁移,这将有所帮助。

从特定的migration_name 开始压缩的最佳方法是什么?

在我目前正在进行的一个项目中,我们添加了 5-10 个新的迁移文件,因为我们添加了新功能。我们将立即部署整个项目,看起来单独运行这些项目将花费太长时间。我想将此项目的所有迁移压缩成一个迁移并测试运行它的时间。

【问题讨论】:

  • 对此进行更新 - 在压缩和测试之后,花费的时间太长了。其中很大一部分是因为对于我添加的每一列,MySQL 会复制整个表,添加列,然后重命名表。我使用 sqlmigrate 查看将运行的 SQL,并将四个单独的 ALTER TABLE 语句组合成一个带有四个 ADD COLUMN 部分的 SQL,并使用 migrations.RunSQL 及其 state_operations 参数运行它,以保持迁移状态逻辑满意。跨度>

标签: django django-migrations


【解决方案1】:
python manage.py squashmigrations <appname> <squashfrom> <squashto>

python manage.py help squashmigrations

https://docs.djangoproject.com/en/dev/topics/migrations/#migration-squashing

这将使您能够更精细地控制要压缩的迁移,并让您保持更清晰的提交历史记录。删除 + 重新创建所有迁移可能会导致其他问题,例如循环依赖,具体取决于模型的构建方式。

【讨论】:

  • 好答案 -- if 运行 Django 1.9 或更高版本。可悲的是,这个项目是在 1.8
  • 这得到了公认的答案,因为它使用了现代版 Django 的原生功能。那些仍在使用 1.9 之前版本的 Django 的人应该看到 Dan 的回答。
  • 为了省去阅读所有长迁移文件名的麻烦。您可以使用前 4 位数字,例如 manage.py squashmigrations myapp 0011 0015 将迁移 0011_auto_someintshere 压缩到 0015_auto_someintshere
【解决方案2】:

您可以删除迁移文件并再次运行makemigrations。如果您有使用这些的开发部署,您应该 migrate back 到您删除的第一个之前的那个。

另外,最好先提交代码,以防出现问题。

还有:

这有点复杂,如果有自定义的 RunPython 代码,它不会包含在 makemigrations 创建的新迁移中

【讨论】:

  • 如此明智和明显。我也会在一个分支中做:-)
  • 稍微复杂一点的是,如果有自定义的RunPython 代码,它将不会包含在makemigrations 创建的新迁移中
  • 如果您删除选定的迁移(比如__init__ 之后的所有迁移),然后运行makemigrations 并看到类似You have 1 unapplied migration(s) 的消息,您可以运行./manage.py migrate --fake 来“伪造”迁移(虽然其他团队成员将获得完整的迁移)。
  • 我一直想知道这一点。我一直在为进行如此多的迁移而苦苦挣扎,但Django recommends it explicitly。我想这取决于场景,例如RunPython、您的开发团队成员等。感谢您在混乱中指出显而易见的事情。
【解决方案3】:

我创建了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 中,您会发现replaces = [..] 带有迁移1-5 的名称。如果您删除所有迁移并执行./manage.py makemigrations + 任何RunSQL/RunPythonelidable=False,您还将找到一个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

再次开始循环。

【讨论】:

    【解决方案4】:

    Squash 迁移命令在 Django 1.9 中引入

    如果您使用的是 Django 1.8,则需要

    【讨论】:

      猜你喜欢
      • 2021-01-13
      • 2016-06-14
      • 2015-11-12
      • 2015-08-18
      • 2016-10-09
      • 2020-12-18
      • 2014-10-19
      • 1970-01-01
      • 2018-03-13
      相关资源
      最近更新 更多