在Django中向后迁移DeleteModel时出错

时间:2019-05-03 16:35:39

标签: python django postgresql psycopg2 django-migrations

在具有PostgreSQL的Django 1.11中,我有两个具有一对一关系的模型。这两个模型在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'),
        ),
    ]

这些实现已成功运行。除了这种迁移,我们还进行了其他一些与项目其他任务相关的迁移。

由于我们今天进行了设计更改,因此我们决定将所有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)
    ]

正如代码说明的那样,此迁移将每个非空的图书信息数据推送到我们的云存储中,并用数据库中的空dict替换它。我已经来回测试了此迁移,并确保正向和反向迁移都能成功进行。

然后,为摆脱多余的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

我看到了这个https://github.com/webdevelopers-eu/jquery-dna-template/。为此,我这次通过使用Book参数来手动重新创建book模型和Author模型的OneToOneField blank=True, null=True字段。但是,在我成功地应用了上面的迁移之后,向后迁移时也会遇到相同的例外情况。

可能是什么问题?

1 个答案:

答案 0 :(得分:0)

我设法通过更改迁移顺序来解决问题。

正如我在问题中提到的,我通过在blank=True, null=Trueinfo字段中添加book参数来应用this answer。但是它的相关迁移文件是在将我们的图书信息移动到云存储的迁移文件之后创建的。当我更改了这两个迁移文件的顺序后,问题就解决了。