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