Django数据迁移中的手动提交

Django数据迁移中的手动提交,django,postgresql,database-migration,Django,Postgresql,Database Migration,我想编写一个数据迁移,在这个迁移中,我以较小的批量修改一个大表中的所有行,以避免锁定问题。但是,我不知道如何在Django迁移中手动提交。每次尝试运行commit时,我都会得到: TransactionManagementError:当“原子”块处于活动状态时,这是禁止的 一开始,这是一个很好的例子 是否有一种合理的方法可以从迁移中中断事务? 我的迁移如下所示: def modify_data(apps, schema_editor): counter = 0 BigData =

我想编写一个数据迁移,在这个迁移中,我以较小的批量修改一个大表中的所有行,以避免锁定问题。但是,我不知道如何在Django迁移中手动提交。每次尝试运行
commit
时,我都会得到:

TransactionManagementError:当“原子”块处于活动状态时,这是禁止的

一开始,这是一个很好的例子

是否有一种合理的方法可以从迁移中中断事务?

我的迁移如下所示:

def modify_data(apps, schema_editor):
    counter = 0
    BigData = apps.get_model("app", "BigData")
    for row in BigData.objects.iterator():
        # Modify row [...]
        row.save()
        # Commit every 1000 rows
        counter += 1
        if counter % 1000 == 0:
            transaction.commit()
    transaction.commit()

class Migration(migrations.Migration):
    operations = [
        migrations.RunPython(modify_data),
    ]
我使用的是Django1.7和Postgres9.3。这用于处理Django的南方版本和旧版本。

来自:

默认情况下,RunPython将在不支持DDL事务的数据库(例如MySQL和Oracle)上的事务内部运行其内容。这应该是安全的,但是如果您试图使用这些后端上提供的schema_编辑器,可能会导致崩溃;在本例中,将atomic=False传递给RunPython操作

因此,与其说你得到了什么,不如说:

类迁移(migrations.Migration):
操作=[
RunPython(modify_data,atomic=False),
]

我发现的最佳解决方法是在运行数据迁移之前手动退出原子作用域:

def modify_data(apps, schema_editor):
    schema_editor.atomic.__exit__(None, None, None)
    # [...]
与手动重置
连接相反。在_atomic_块
中,这允许在迁移内部使用
atomic
上下文管理器。似乎没有比这更明智的方法了

可以在一个decorator中包含(公认的混乱)事务中断逻辑,用于
RunPython
操作:

def non_atomic_migration(func):
  """
  Close a transaction from within code that is marked atomic. This is
  required to break out of a transaction scope that is automatically wrapped
  around each migration by the schema editor. This should only be used when
  committing manually inside a data migration. Note that it doesn't re-enter
  the atomic block afterwards.
  """
  @wraps(func)
  def wrapper(apps, schema_editor):
      if schema_editor.connection.in_atomic_block:
          schema_editor.atomic.__exit__(None, None, None)
      return func(apps, schema_editor)
  return wrapper
更新


Django 1.10将为遇到此问题的其他人提供支持。

。您可以在同一迁移中同时拥有这两个数据(RunPython)。只要确保所有的alter表格都是先到的。您不能在任何ALTER TABLE之前运行Python。

谢谢。我已经试过了,但它实际上并没有删除迁移过程中的原子上下文(至少对于Postgres而言),因为这里是django.db.migration.py中的代码:
如果不是模式编辑器.connection.features.can\u rollback\u ddl和操作.原子:
-
如果不是模式编辑器.connection.features.can\u rollback\u ddl和操作.原子:带有原子(模式编辑器.connection.alias):…
。你确定没有其他事情发生了吗?可能在那里设置一个断点(django 1.8中的第109行)?是的,这避免了使操作原子化,但数据库模式编辑器仍然使整个迁移原子化:噢。很可能您没有想到这一点,唯一的方法可能就是执行
connection.cursor().execute(“COMMIT;”)
,尽管您确实需要一种“理智”的方法:这肯定不理想,但看起来似乎没有办法解决。感谢您的提示,如果我还设置了
connection.in\u atomic\u block=False
,这实际上是可行的。查看记录的SQL语句,这实际上可以正常工作(在适当的位置开始/提交)。然而,我觉得你不应该打破一个原子块(用理智的代码)。这使得使用Django编写更复杂的数据迁移变得非常困难。Django 1.9.5:
AttributeError:'DatabaseSchemaEditor'对象没有属性'atomic'