承诺南方数据迁移

时间:2014-06-04 17:57:20

标签: python django django-south

如何在南方数据迁移中执行手动提交?

我创建了一个长期运行的南方数据迁移。默认情况下,South似乎将整个迁移包装在单个事务中。但是,由于我正在修改数百万行,如果我尝试在单个事务中存储所有挂起的更改,这将导致数据库占用我的所有系统内存。

为了防止这种情况,我试图在每N条记录中调用Django的commit(),但这会抛出异常:

TransactionManagementError: This code isn't under transaction management

即使我使用forwards()包裹迁移的@commit_on_success方法或在[commit_manually()][1]的开头调用forwards,我仍然会在调用{{1}时遇到异常或南方自己的commit()

我该如何解决这个问题?

编辑:如果我用db.commit_transaction()包裹forwards(),这会修复错误,但是,@commit_manually似乎仍然没有实际提交更改。

我的代码如下:

commit()

我的总数约为300万。当它正在运行时,我将从SQL终端class Migration(DataMigration): @commit_manually def forwards(self, orm): mdl = orm['myapp.MyModel'] q = mdl.filter(criteria=value_to_change).only('id') total = q.count() i = 0 pending = [] tmp_debug = settings.DEBUG settings.DEBUG = False try: for record in q.iterator(): i += 1 if i == 1 or not i % 10 or i == total: print '\rProcessing %i of %i.' % (i, total), sys.stdout.flush() mdl.objects.filter(id__in=pending).update(criteria=new_value) pending = [] # These don't seem to do anything, as the changes above aren't visible. #commit() db.commit_transaction() pending.append(record.id) finally: settings.DEBUG = tmp_debug 进行查询,并且显示的计数永远不会改变。

但是,如果我改变上面的代码来执行select count(*) from myapp_mymodel where criteria=value_to_change所以它几乎立即完成,我的SQL查询会在迁移完成后显示更改,这意味着我的q = q[:100]什么都不做,而且commit()是真的{{ 1}}仅在commit()完成后运行。造成这种情况的原因是什么?

1 个答案:

答案 0 :(得分:1)

您可以按块检索行,手动启动事务并在每个已处理的块之后提交事务。

这里描述的主要想法(经过测试!):

def queryset_iterator(queryset, chunksize=1000):
    pk = 0
    last_pk = queryset.order_by('-pk')[0].pk
    queryset = queryset.order_by('pk')
    while pk < last_pk:
        db.commit_transaction()  # Commit the first transaction
        db.start_transaction()  # Start the second, committed on completion
        for row in queryset.filter(pk__gt=pk)[:chunksize]:
            pk = row.pk
            yield row

qs = orm['myapp.MyModel'].filter(criteria=value_to_change).only('id')
for row in queryset_iterator(qs):
    row.criteria=new_value
    row.save()

希望这些帮助!