恢复Django 1.7 RemoveField迁移

时间:2015-03-05 12:58:08

标签: 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.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

当然,这是预期的行为,它是clearly documented,我不是在问为什么会这样:

  

请记住,当反转时,这实际上是在a中添加一个字段   模型;如果该字段不可为空,则可以进行此操作   不可逆转的(除了任何数据丢失,当然是   不可逆的)。

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

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

4 个答案:

答案 0 :(得分:21)

您可以手动编辑迁移,并为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 :(得分:4)

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

  1. 使字段可以为空
  2. 数据迁移。转发,不要做任何事情。向后,将空值转换为存根值。
  3. 删除字段
  4. 这三个步骤中的每一步都应该是可逆的。

    如果您已经运行了迁移并需要撤消迁移,则可以

    1. 手动添加字段,允许空值
    2. 将空值转换为存根值
    3. 手动添加非空约束
    4. 使用--fake迁移到上一次迁移

答案 2 :(得分:0)

最简单的方法可能是使用migrations.RunSQL

您可以编辑迁移,以便您的operations列表如下所示:

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

那将是一个棘手的解决方案,但其他任何解决方案也可能如此。

答案 3 :(得分:0)

只需在旧迁移中将 'default' 和 'preserve_default' 添加到您的 AddField 或 AddModel 中,Django 就会知道它必须使用提供的默认值重新创建列

This Helped me