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编写完整的脚本,可以使用一组手动说明。如果您试图使将来的迁移可逆,您可以尝试在三次迁移时删除该字段
--伪迁移到上一次迁移
您可以手动编辑迁移,并在
RemoveField
之前添加带有默认值的AlterField
。即使在应用迁移之后,它也应该是安全的。这将使之后发生的RemoveField
成为可逆的
举个例子。在modelsummary
中有名为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。