重新运行 Django 数据迁移

Rerun a Django data migration

如何在 Django 1.8+ 上重新运行数据迁移?如果相关,我的迁移编号为 0011_my_data_migration.py,并且是最新的迁移。

假回迁移到你想重新迁移的那个之前运行。

./manage.py migrate --fake yourapp 0010_my_previous_data_migration

然后重新运行迁移。

./manage.py migrate yourapp 0011_my_data_migration

然后您可以伪造回您拥有的最近一次迁移 运行。在你的情况下,你说0011是最新的,所以你可以跳过这个阶段。

./manage.py migrate --fake yourapp 0014_my_latest_data_migration

请注意,根据数据库的状态和迁移的内容,重新运行这样的迁移可能会导致错误。请注意有关 --fake 选项的警告 in the docs

This is intended for advanced users to manipulate the current migration state directly if they’re manually applying changes; be warned that using --fake runs the risk of putting the migration state table into a state where manual recovery will be needed to make migrations run correctly.

Alasdair 的回答给出了关于此的免责声明,但只有在您的迁移是幂等的情况下,伪造迁移回之前的迁移才是安全的,这意味着您可以多次 运行 它而不会产生重复数据等副作用。大多数人不会以这种方式编写迁移,但这是一种很好的做法。

您有两个选项可以确保此过程安全:

  1. 使您的数据迁移幂等。这意味着任何创建的数据要么被重用(如使用 Model.objects.get_or_create() 方法),要么被删除并重新创建。重用是更好的选择,因为删除和重新创建会更改数据库索引和序列。
  2. 进行反向数据迁移。您可以通过将 2 个函数传递给 migrations.RunPython() 来完成此操作。例如,如果您有 migrations.RunPython(add_countries),您可以将其更改为 migrations.RunPython(add_countries, remove_countries) 并删除第二个函数中的所有相关国家/地区。

如果您选择选项 #2,那么您会 运行:

./manage.py migrate yourapp 0010_my_previous_data_migration
./manage.py migrate yourapp 0011_my_data_migration

如果你想把它做成一个衬里,这样你就可以一遍又一遍地使用它:

./manage.py migrate yourapp 0010_my_previous_data_migration && ./manage.py migrate yourapp 0011_my_data_migration

根据已接受的答案,这里有一个用于重新应用给定迁移的脚本。

#! /bin/bash
# This script re-applies a given migration.
app_name=""
migration_index=""

prev_migration_index="$(echo "$migration_index" | sed 's/^0*//' | awk '{ print  - 1 }' | xargs printf "%04d")"
last_migration_index="$(django-admin showmigrations --plan | grep -oP "\.\K\d{4}" | sort | tail -n 1)"

# fake-migrate to the migration prior to the one we want to reapply
django-admin migrate --fake "$app_name" "$prev_migration_index"
# reapply the migration
django-admin migrate "$app_name" "$migration_index"
# fake-migrate to the last migration
django-admin migrate --fake "$app_name" "$last_migration_index"

用法:

$ bash reapply_migration.sh <app_name> <migration_to_reapply_index>