如何压制最近的 Django 迁移?

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

所以,如果你想压制,比如说,前5次迁移,这会有所帮助。

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

在我目前正在做的一个项目中,我们已经添加了5-10个新的迁移文件,因为我们已经添加了新的特性。我们将立即部署整个项目,看起来单独运行这些项目会花费太长时间。我希望将这个项目的所有迁移压缩到一个迁移中,并测试运行这个迁移的时间。

49956 次浏览

You can just delete the migration files and run makemigrations again. If you have a dev deployment that uses these, you should migrate back to the one before the first one you delete.

Also, it's probably a good idea to commit your code first, in case something goes wrong.

Also:

The slight complication with this is that if there's custom RunPython code, it won't be included in the new migration created by makemigrations

python manage.py squashmigrations <appname> <squashfrom> <squashto>


python manage.py help squashmigrations

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

This will give you more granular control over which migrations to squash, and let you keep a cleaner commit history. Deleting + recreating all migrations may cause other issues such as circular dependencies depending on how models are constructed.

I created django-squash https://pypi.org/project/django-squash/ as a way to not have to deal with migrations on a per-app level or worse a per-app-specific-migration level, and handle it on a per-project level. The idea is to hopefully integrate it inside core Django at some point.

Basic idea:

  • You have a product, nothing open source that other people enhance, but yours, your teams, you deal with it.
  • After each release you want to squash all migrations you did in the past release and start a new because your product has evolved from what it was last release and your data model as well.
  • You squash, it looks to see if you've squashed previously, if you have, it will deleted any VERY old migrations that have no business in your codebase anymore. Finally, create a new snapshot of your migrations, and keep what migrations you had around.
  • You will do this every release/when ever you feel your tests are taking too long running all your migrations.

Example:

/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

You've applied them all.

But every time you run your tests, every single one of those steps need to run, taking valuable time. So we squash. The new directory will look like this:

/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

inside 0006_squash.py you will find a replaces = [..] with the names of migrations 1-5. You will also find a Migration.operations = [..] with everything you would expect if you deleted all your migrations and did a ./manage.py makemigrations + any RunSQL/RunPython with elidable=False. If you deploy to an environment that is missing any of migrations 1-5 it will apply it from source and not use 0006 AT ALL. (this is standard Django migrations)

Some time passes, now your migrations look like this:

/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

You squash again. This time the following will happen. Anything inside the replaces = [..] will be deleted. 0006_squash.py will be modified to have replaces be an empty list. Lastly the squash will be recreated with the new changes. All told, will look like this:

/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

Starting the cycle once again.

Squash migrations command was introduced in Django 1.9

If you are using Django 1.8 you need to