在 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 上的数据迁移中,直到原子块结束才能执行查询的主要内容,如果未能解决你的问题,请参考以下文章

在迁移中获取模型 ContentType - Django 1.7

Django 1.7 中的迁移

Django 1.7 迁移不会重新创建删除的表,为啥?

我的旧项目出现 Django 1.7 迁移问题

Django 1.7 内置迁移与南迁移?

Django 1.7 迁移挂起