Ошибка при обратной миграции DeleteModel в Django - PullRequest
1 голос
/ 03 мая 2019

У меня есть две модели с отношением один к одному в Django 1.11 с PostgreSQL.Эти две модели определены в models.py следующим образом:

class Book(models.Model):
    info = JSONField(default={})


class Author(models.Model):
    book = models.OneToOneField(Book, on_delete=models.CASCADE)

Автоматически созданный файл миграции для этих моделей имеет вид:

class Migration(migrations.Migration):

    dependencies = [
        ('manager', '0018_some_migration_dependency'),
    ]

    operations = [
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('info', JSONField(default={})),
            ],
        ),
        migrations.AddField(
            model_name='author',
            name='book',
            field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='manager.Book'),
        ),
    ]

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

В связи с нашими изменениями в дизайне, которые мы сделали сегодня, мы решили перенести все данные о книге в наше облачное хранилище.,Чтобы сделать это, я реализовал пользовательский код миграции следующим образом:

def push_info_to_cloud(apps, schema_editor):

    Author = apps.get_model('manager', 'Author')
    for author in Author.objects.all():
        if author.book.info is not None and author.book.info != "":

            # push author.book.info to cloud storage

            author.book.info = {}
            author.book.save()


def pull_info_from_cloud(apps, schema_editor):

    Author = apps.get_model('manager', 'Author')
    Book = apps.get_model('manager', 'Book')
    for author in Author.objects.all():

            # pull author.book.info back from cloud storage

            book = Book.objects.create(info=info)
            author.book = book
            author.save()


class Migration(migrations.Migration):

    dependencies = [
        ('manager', '0024_some_migration_dependency'),
    ]

    operations = [
        migrations.RunPython(push_info_to_cloud, pull_info_from_cloud)
    ]

Как говорит сам код, эта миграция передает все данные о ненулевой книге в наше облачное хранилище и заменяет их напустой дикт в базе данных.Я проверил эту миграцию взад и вперед и убедился, что прямая и обратная миграция работают успешно.

Затем, чтобы избавиться от избыточной таблицы Book и столбца book в таблице Author,Я удалил модель Book и поле книги OneToOneField в модели Author и запустил manage.py makemigrations, что привело к следующему автоматически сгенерированному коду миграции:

class Migration(migrations.Migration):

    dependencies = [
        ('manager', '0025_some_migration_dependency'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='user',
            name='book',
        ),
        migrations.DeleteModel(
            name='Book',
        ),
    ]

Запуск manage.py migrateсделал сработало.В итоге таблица Book и столбец book таблицы Author будут удалены.

Теперь проблема в том, чтоКогда я хочу перейти обратно на 0024_some_migration_dependency, я получаю следующую ошибку во время выполнения последнего файла миграции:

  Unapplying manager.0026_auto_20190503_1702...Traceback (most recent call last):
  File "/home/cagrias/Workspace/Project/backend/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
psycopg2.IntegrityError: column "book_id" contains null values

Я видел этот ответ .Чтобы попробовать это, я вручную заново создал модель Book и поле OneToOneField book модели Author, используя параметры blank=True, null=True на этот раз.Но после того, как я успешно применил описанные выше миграции, я получил те же исключения при миграции назад.

В чем может быть проблема?

1 Ответ

0 голосов
/ 08 мая 2019

Мне удалось решить проблему, изменив порядок миграций.

Как я уже упоминал в своем вопросе, я применил этот ответ , добавив blank=True, null=True параметры в оба поля info и book. Но связанный с ним файл миграции был создан после файла миграции, который перемещает информацию о нашей книге в облачное хранилище. Когда я изменил порядок этих двух файлов миграции, проблема была решена.

...