在django 1.7上的数据迁移中,直到原子块结束才能执行查询

时间:2015-08-25 13:22:57

标签: django data-migration

我有一个很长的数据迁移,我正在做的是纠正早先的错误迁移,其中某些行创建不正确。我正在尝试根据旧列为新列分配值,但是,有时这会导致完整性错误。当发生这种情况时,我想扔掉导致完整性错误的那个

以下是代码段:

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():
某处是我的解决方案,但我不确定正确的地方在哪里。更重要的是,我想了解为什么这是必要的

3 个答案:

答案 0 :(得分:17)

这类似于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。通过将代码包装在原子块中,只会回滚该代码,并且可以在块之外执行查询。

答案 1 :(得分:0)

每次迁移都围绕一个事务处理,因此当迁移期间出现故障时,所有操作都将被取消。因此,每次事务失败的事务都不能接受新的查询(无论如何都会被取消)。

使用with transaction.atomic():包装某些操作并不是一个好方法,因为当某些操作失败时,您将无法取消该操作。而不是那样,通过在保存数据之前进行更多检查来避免完整性错误。

答案 2 :(得分:0)

似乎同一异常可能有多种原因。在我的情况下,这是由无效的模型字段名称引起的:我在字段名称中使用了希腊字母delta

它似乎运行良好,所有应用程序都运行良好(也许我只是没有尝试任何更复杂的用例)。但是测试引发了TransactionManagementError

我通过从字段名称和所有迁移文件中删除解决了该问题。