Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Revert Django 1.7 RemoveField迁移_Django_Django South_Django 1.7_Django Migrations - Fatal编程技术网

Revert Django 1.7 RemoveField迁移

Revert Django 1.7 RemoveField迁移,django,django-south,django-1.7,django-migrations,Django,Django South,Django 1.7,Django Migrations,如果我有一个不可为空的模型字段,请将其删除,然后创建迁移,该迁移将变得不可逆: 考虑以下模型: 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.Migrati

如果我有一个不可为空的模型字段,请将其删除,然后创建迁移,该迁移将变得不可逆:

考虑以下模型:

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',
        ),
    ]
取消应用此迁移会引发异常:

$ 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
当然,这是预期的行为,我不是在问为什么会发生这种情况:

请记住,当反转时,实际上是将字段添加到 模型如果该字段不可为空,则可能会执行此操作 不可逆转(除了任何数据丢失,当然是 不可逆转)

然而,我们都会犯错误,有时我们只是需要以某种方式反转字段删除,即使这意味着手动为所有反转的非空字段提供临时存根值。例如,South migrations可以选择允许反转这些操作(通过询问开发人员是否为恢复的字段提供默认值,或者不允许反转迁移),而所有新的fancy Django 1.7迁移似乎都不是这样


问题:使用Django 1.7+迁移撤消字段删除的最简单/最快方法是什么(假设已经发生)?不一定需要使用Python编写完整的脚本,可以使用一组手动说明。

如果您试图使将来的迁移可逆,您可以尝试在三次迁移时删除该字段

  • 使字段为空
  • 数据迁移。前进,不要做任何事。向后,将空值转换为存根值
  • 删除字段
  • 这三个步骤中的每一步都应该是可逆的

    如果您已经运行了迁移并需要将其反转,则可以

  • 手动添加字段,允许为空
  • 将空值转换为存根值
  • 手动添加NOTNULL约束
  • 使用
    --伪
    迁移到上一次迁移

  • 您可以手动编辑迁移,并在
    RemoveField
    之前添加带有默认值的
    AlterField
    。即使在应用迁移之后,它也应该是安全的。这将使之后发生的
    RemoveField
    成为可逆的

    举个例子。在model
    summary
    中有名为
    profit
    的字段,该字段在删除之前定义如下:

    profit = models.PositiveIntegerField(verbose_name='profits')
    
    migrations.AlterField(
        model_name='summary',
        name='profit',
        field=models.PositiveIntegerField(verbose_name='profits', default=0),
        preserve_default=False,
        ),
    
    您应该在其
    RemoveField
    之前添加一个
    AlterField
    ,如下所示:

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

    最简单的方法可能是使用
    迁移。RunSQL

    您可以编辑迁移,使您的
    操作
    列表如下所示:

    operations = [
        sql=[('alter table foo_test drop test)],
        reverse_sql=[('alter table foo_test add test varchar)]
    ]
    

    这将是一个骇人的解决方案,但其他任何解决方案也可能如此

    我不太确定第1步中的“手动添加字段”。我当然希望避免手动运行ALTER TABLE。。添加列,这是ORM层经常做和应该做的事情。程序员不必重复ORM所做的所有小技巧(命名字段、管理索引等),手动运行SQL并不理想,但有时您可能没有其他选择。其他人可能会有更好的建议。您可能可以让Django使用
    /manage.py sqlmigrate--backwards
    生成SQL。我可以确认
    /manage.py sqlmigrate--backwards
    提供了正确的SQL来执行此迁移,并且如果您使用的是像PyCharm这样的IDE,那么运行此操作并不痛苦;迁移编辑方法在向后迁移时对我不起作用。
    AlterField
    不接受
    preserve\u default
    参数(但在这种情况下似乎不需要它,因为
    default
    无论如何都不会进入数据库架构)。除此之外,这似乎确实是一个正确和最佳的解决方案。谢谢根据,是的,但它是在1.7.1中添加的。在这种情况下,违约就不重要了。在Django 1.8中,我使用了
    preserve\u default=True
    @emyller,我添加了RunPythons来创建和删除相关模型表中的虚拟对象,以便默认值指向某个对象,它起作用了:)我尝试使用
    AlterField
    在删除字段之前使其为空(而不是提供默认值),但它不起作用。知道为什么吗?我的意思是,Django如何判断数据库中不存在的字段是不可为空的,如果不是通过查看迁移文件中的修改的话?在反向迁移期间执行
    RemoveField
    操作之前,必须有一种方法可以强制该字段为null。