在 django 1.7 上的数据迁移中的原子块结束之前无法执行查询
Can't execute queries until end of atomic block in my data migration on django 1.7
我有一个很长的数据迁移,我正在做它来纠正早期错误的迁移,其中一些行创建不正确。我正在尝试根据旧列将值分配给新列,但是,有时这会导致完整性错误。发生这种情况时,我想扔掉导致完整性错误的那个
这是一个代码片段:
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
class 我做
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():
某处是我的解决方案,但我不确定正确的地方在哪里。更重要的是,我想了解为什么这是必要的
这类似于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()
文档中的警告块 'Avoid catching exceptions inside atomic!' 中解释了错误原因。一旦 Django 遇到数据库错误,它会回滚原子块。尝试任何更多的数据库查询将导致您看到的 TransactionManagementError
。通过将代码包装在原子块中,只有该代码会回滚,您可以在块外执行查询。
每次迁移都围绕一个事务进行,因此当迁移过程中出现问题时,所有操作都将被取消。正因为如此,每个失败的交易都不能接受新的查询(无论如何它们都会被取消)。
用 with transaction.atomic():
包装一些操作不是好的解决方案,因为当某些操作失败时您将无法取消该操作。相反,通过在保存数据之前进行更多检查来避免完整性错误。
看来同一个异常可能有多种原因。在我的例子中,它是由无效的模型字段名称引起的:我在字段名称中使用了希腊字母 delta </code>。</p>
<p>它似乎工作正常,所有应用程序都运行良好(也许我只是没有尝试任何更复杂的用例)。然而,测试提出了 <code>TransactionManagementError
.
我通过从字段名称和所有迁移文件中删除
解决了这个问题。
我遇到了同样的问题,但我使用 django.test.TransactionTestCase
而不是 django.test.TestCase
解决了它。
我有一个很长的数据迁移,我正在做它来纠正早期错误的迁移,其中一些行创建不正确。我正在尝试根据旧列将值分配给新列,但是,有时这会导致完整性错误。发生这种情况时,我想扔掉导致完整性错误的那个
这是一个代码片段:
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
class 我做
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():
某处是我的解决方案,但我不确定正确的地方在哪里。更重要的是,我想了解为什么这是必要的
这类似于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()
文档中的警告块 'Avoid catching exceptions inside atomic!' 中解释了错误原因。一旦 Django 遇到数据库错误,它会回滚原子块。尝试任何更多的数据库查询将导致您看到的 TransactionManagementError
。通过将代码包装在原子块中,只有该代码会回滚,您可以在块外执行查询。
每次迁移都围绕一个事务进行,因此当迁移过程中出现问题时,所有操作都将被取消。正因为如此,每个失败的交易都不能接受新的查询(无论如何它们都会被取消)。
用 with transaction.atomic():
包装一些操作不是好的解决方案,因为当某些操作失败时您将无法取消该操作。相反,通过在保存数据之前进行更多检查来避免完整性错误。
看来同一个异常可能有多种原因。在我的例子中,它是由无效的模型字段名称引起的:我在字段名称中使用了希腊字母 delta </code>。</p>
<p>它似乎工作正常,所有应用程序都运行良好(也许我只是没有尝试任何更复杂的用例)。然而,测试提出了 <code>TransactionManagementError
.
我通过从字段名称和所有迁移文件中删除 解决了这个问题。
我遇到了同样的问题,但我使用 django.test.TransactionTestCase
而不是 django.test.TestCase
解决了它。