用non_atomic_requests替换django装饰器commit_manually

时间:2019-06-05 21:33:41

标签: python django django-views

我有一个导入Excel文件的Django视图,如果发生异常,我想捕获它们并报告所有异常,并回滚所有保存。即使使用了non_atomic_requests装饰器,我也遇到了TransactionManagementError。

  1. 由于我也在使用login_required装饰器,因此我认为它们可能会相互干扰。首先,我颠倒了顺序,然后删除了所需的登录名。没变化。

  2. 我尝试了全局禁用自动交易。也许我做的不对,但这仍然不是我想要的解决方案。

  3. 我删除了有问题的代码行(见下文),但是当我尝试回滚时发生了相同的错误

它在具有最新Django的Python 3.7.3上运行,并使用SQLlite。我现在正在将其作为单元测试运行,尽管也许我在滥用该术语。可以说它作为Django TestCase运行。

@transaction.non_atomic_requests
@login_required(login_url='/accounts/login/?next=/finance/gl_upload/')
def gl_upload(request):
    transaction.set_autocommit(False)
    if upriv(request.user, ['admin', 'finance']) == 'admin':
        if request.method == 'POST':

... file processing here ...

                except Exception as e:
                    errs.append(format('Exception "{1}" at row {0}\n'.format(p['rownum'], e)))
                if errs:
                    transaction.rollback()
                    rows_deleted = 0
                    rows_inserted = 0
                    print(''.join('Error: {0}\n'.format(e) for e in errs))
                else:
                    transaction.commit()
                    rows_deleted = Gldata.objects.filter(item='Actual', period_gte=older, period_lte=newest).delete()
                    rows_inserted = Gldata.objects.filter(item=temp_item).update(item='Actual')
                transaction.set_autocommit(True)
                print('Deleted: {0}, inserted: {1}'.format(rows_delete, rows_inserted))
                return render(request, 'gl_upload.html', {'inserted': rows_inserted, 'removed': rows_deleted, 'errors': errs})
            else:
                return render(request, 'gl_upload.html', {'form': form})
        else:
            form = uploadForm()
            return render(request, 'gl_upload.html', {'form': form})

我在set_autocommit上收到一个TransactionManagementError,指示一个原子块处于活动状态,即使我知道装饰器会禁用它。几年前,我使用了旧的commit_manually装饰器,效果很好。

g_upload中的文件“ C:\ Users \ csullivan \ response \ finance \ views.py”,第25行     transaction.set_autocommit(False)   set_autocommit中第30行的文件“ C:\ Users \ csullivan \ response \ env \ lib \ site-packages \ django \ db \ transaction.py”     返回get_connection(using).set_autocommit(autocommit)   set_autocommit中第394行的文件“ C:\ Users \ csullivan \ response \ env \ lib \ site-packages \ django \ db \ backends \ base \ base.py”     self.validate_no_atomic_block()   文件“ C:\ Users \ csullivan \ response \ env \ lib \ site-packages \ django \ db \ backends \ base \ base.py”,第433行,在validate_no_atomic_block中     “当“原子”块处于活动状态时,这是禁止的。”) django.db.transaction.TransactionManagementError:当“原子”块处于活动状态时,这是禁止的。

1 个答案:

答案 0 :(得分:1)

我认为atomic() 装饰器/上下文管理器提供了您所需要的 -如果基础代码成功执行并回滚,则提交事务 出现异常时。

所以在您的情况下,我会这样做:

requirements.txt

您不需要手动调用with atomic(): process_xls_files() 和类似的低级方法, 除非您有非常特定的需求并且“常规”交易处理还不够。