Отменить миграцию Django 1.7 RemoveField

Если у меня есть ненулевое поле модели, удалите его и создайте миграцию, эта миграция станет необратимой:

рассмотрим следующую модель:

class Foo(models.Model):
    bar = models.TextField()
    test = models.TextField()  # This field is to go away, bye-bye!

и миграции:

# app/migrations/003_remove_foo_test.py

class Migration(migrations.Migration):

    dependencies = [
        ('app', '0002_foo_test'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='foo',
            name='test',
        ),
    ]

Unapplying эта миграция вызывает исключение:

$ src/manage.py migrate app 0002
Operations to perform:
  Target specific migration: 0002_foo_test, from app
Running migrations:
  Unapplying app.0003_remove_foo_test...Traceback (most recent call last):
...
django.db.utils.IntegrityError: column "test" contains null values

конечно, это ожидаемое поведение, это четко документированы и я не спрашиваю, почему это происходит:

имейте в виду, что при реверсировании это фактически добавление поля модель; если поле не является nullable это может сделать эту операцию необратимый (помимо любой потери данных, которая, конечно, необратимый.)

тем не менее, мы все делаем ошибки, и иногда мы просто нужно to как-то отменить удаление Поля, даже если это означает ручное предоставление специального заглушки для всех отмененных ненулевых полей. Например, миграция на юг при необходимости позволяет такие операции (путем запроса разработчика о том, следует ли предоставить значение по умолчанию для восстановленных полей или запретить обратную миграцию), что, похоже, не относится ко всем новым миграциям fancy Django 1.7.

вопрос: каков самый простой/быстрый способ отменить удаление Поля с помощью миграции Django 1.7+ (если это уже произошло)? это не обязательно должно быть полностью сценарий с Python, набор ручных инструкций будет делать.

2 ответов


вы можете вручную отредактировать миграцию и добавить AlterField со значением по умолчанию для поля непосредственно перед RemoveField. Он должен быть безопасным даже после применения миграции. Это сделает RemoveField это произойдет после того, чтобы быть обратимым.

пример. Наличие поля в модели summary имени profit это было определено перед удалением, как это:

profit = models.PositiveIntegerField(verbose_name='profits')

вы должны добавить перед RemoveField сюда AlterField вот так:

migrations.AlterField(
    model_name='summary',
    name='profit',
    field=models.PositiveIntegerField(verbose_name='profits', default=0),
    preserve_default=False,
    ),

Если вы пытаетесь сделать будущие миграции обратимыми, вы можете попробовать удалить поле как три миграции.

  1. сделать поле nullable
  2. миграция данных. Вперед, ничего не делай. В обратном порядке преобразуйте нули в заглушку.
  3. удалить поля

каждый из этих трех шагов должен быть обратимым.

Если вы уже выполнили миграцию и вам нужно ее отменить, вы можете

  1. вручную добавьте поле, разрешив nulls
  2. преобразование нулей в значение заглушки
  3. вручную добавьте ограничение not null
  4. миграция с --fake к предыдущей миграции