如果我有一个不可为空的模型字段,删除它,并创建一个迁移,那么迁移变得不可逆:
考虑以下模型:
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编写脚本,一套手动指令就可以了。
答案 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)
如果您尝试使将来的迁移可逆,您可以尝试将该字段删除为三次迁移。
这三个步骤中的每一步都应该是可逆的。
如果您已经运行了迁移并需要撤消迁移,则可以
--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 就会知道它必须使用提供的默认值重新创建列