У меня есть две модели с отношением один к одному в 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
на этот раз.Но после того, как я успешно применил описанные выше миграции, я получил те же исключения при миграции назад.
В чем может быть проблема?