在 django 1.7 上的数据迁移中,直到原子块结束才能执行查询
Posted
技术标签:
【中文标题】在 django 1.7 上的数据迁移中,直到原子块结束才能执行查询【英文标题】:Can't execute queries until end of atomic block in my data migration on django 1.7 【发布时间】:2015-11-19 05:30:30 【问题描述】:我进行了相当长的数据迁移,以纠正早期的错误迁移,其中某些行创建不正确。我正在尝试根据旧列将值分配给新列,但是,有时这会导致完整性错误。发生这种情况时,我想丢弃导致完整性错误的那个
这是一个代码sn-p:
def load_data(apps, schema_editor):
MyClass = apps.get_model('my_app', 'MyClass')
new_col_mapping = old_val1: new_val1, ....
for inst in MyClass.objects.filter(old_col=c):
try:
inst.new_col = new_col_mapping[c]
inst.save()
except IntegrityError:
inst.delete()
然后在我的Migration
类的操作中我做
operations = [
migrations.RunPython(load_data)
]
运行迁移时出现以下错误
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block
我有这种感觉
with transaction.atomic():
某处是我的解决方案,但我不确定正确的位置在哪里。更重要的是,我想了解为什么这是必要的
【问题讨论】:
【参考方案1】:这类似于example in the docs。
首先,如果您还没有所需的导入,请添加它。
from django.db import transaction
然后将可能引发完整性错误的代码包装在原子块中。
try:
with transaction.atomic():
inst.new_col = new_col_mapping[c]
inst.save()
except IntegrityError:
inst.delete()
错误原因在警告块“避免在原子内部捕获异常!”中进行了解释。在文档中。一旦 Django 遇到数据库错误,它将回滚原子块。尝试任何更多的数据库查询将导致您看到的TransactionManagementError
。通过将代码包装在一个原子块中,只有该代码会被回滚,并且您可以在该块之外执行查询。
【讨论】:
【参考方案2】:每个迁移都围绕一个事务进行,因此当迁移过程中出现故障时,所有操作都将被取消。因此,每个失败的事务都不能接受新的查询(无论如何它们都会被取消)。
用with transaction.atomic():
包装一些操作不是很好的解决方案,因为当某些操作失败时,您将无法取消该操作。取而代之的是,通过在保存数据之前进行更多检查来避免完整性错误。
【讨论】:
我不确定为什么使用transaction.atomic()
是一个“糟糕”的解决方案,如果这就是我将要做的事情的话。这些行是错误的,实际上是坏的,我想摆脱它们【参考方案3】:
似乎同一个异常可能有多种原因。就我而言,这是由无效的模型字段名称引起的:我在字段名称中使用了希腊字母 delta ?
。
它似乎运行良好,所有应用程序运行良好(也许我只是没有尝试任何更复杂的用例)。然而,测试引发了TransactionManagementError
。
我通过从字段名称和所有迁移文件中删除 ?
解决了这个问题。
【讨论】:
【参考方案4】:我遇到了同样的问题,但我通过使用 django.test.TransactionTestCase
而不是 django.test.TestCase
解决了它。
【讨论】:
以上是关于在 django 1.7 上的数据迁移中,直到原子块结束才能执行查询的主要内容,如果未能解决你的问题,请参考以下文章