Pan*_*rat 15 django postgresql database-migration
我想写一个数据迁移,我在这里以较小的批量修改一个大表中的所有行,以避免锁定问题.但是,我无法弄清楚如何在Django迁移中手动提交.每次我试着跑,commit我得到:
TransactionManagementError:当'atomic'块处于活动状态时禁止使用.
AFAICT,数据库模式编辑器总是在原子块中包装Postgres迁移.
是否有一种明智的方法可以在迁移过程中突破交易?
我的迁移看起来像这样:
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),
]
Run Code Online (Sandbox Code Playgroud)
我正在使用Django 1.7和Postgres 9.3.这曾经用于南方和旧版本的Django.
Pan*_*rat 11
我发现的最佳解决方法是在运行数据迁移之前手动退出原子范围:
def modify_data(apps, schema_editor):
schema_editor.atomic.__exit__(None, None, None)
# [...]
Run Code Online (Sandbox Code Playgroud)
与connection.in_atomic_block手动重置相反,这允许atomic在迁移中使用上下文管理器.似乎没有更多的方式.
可以在装饰器中包含(通常是凌乱的)事务中断逻辑以与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
Run Code Online (Sandbox Code Playgroud)
更新
Django 1.10将支持非原子迁移.
默认情况下,RunPython将在不支持DDL事务的数据库(例如,MySQL和Oracle)上的事务内运行其内容.这应该是安全的,但如果您尝试使用这些后端上提供的schema_editor,可能会导致崩溃; 在这种情况下,将atomic = False传递给RunPython操作.
所以,而不是你有什么:
class Migration(migrations.Migration):
operations = [
migrations.RunPython(modify_data, atomic=False),
]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3922 次 |
| 最近记录: |