Skip to main content
 首页 » 编程设计

python之用 non_atomic_requests 替换 django 装饰器 commit_manually

2024年11月24日22unruledboy

我有一个导入 Excel 文件的 Django View ,如果发生异常,我想捕获它们并全部报告,并回滚任何保存。即使我使用了 non_atomic_requests 装饰器,我仍收到 TransactionManagementError。

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

  2. 我试过在全局范围内禁用自动交易。也许我没有做对,但这不是我想要的解决方案。

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

它在 Python 3.7.3 和最新的 Django 上运行,并使用 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 指示原子 block 处于事件状态,即使我知道装饰器会禁用它。几年前,我使用了旧的 commit_manually 装饰器,它工作得很好。

文件“C:\Users\csullivan\responsive\finance\views.py”,第 25 行,在 gl_upload 中 交易.set_autocommit(假) 文件“C:\Users\csullivan\responsive\env\lib\site-packages\django\db\transaction.py”,第 30 行,在 set_autocommit 中 返回 get_connection(using).set_autocommit(autocommit) 文件“C:\Users\csullivan\responsive\env\lib\site-packages\django\db\backends\base\base.py”,第 394 行,在 set_autocommit 中 self.validate_no_atomic_block() 文件“C:\Users\csullivan\responsive\env\lib\site-packages\django\db\backends\base\base.py”,第 433 行,在 validate_no_atomic_block “当‘原子’ block 处于事件状态时,这是被禁止的。”) django.db.transaction.TransactionManagementError:当“原子” block 处于事件状态时,这是被禁止的。

请您参考如下方法:

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

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

with atomic(): 
  process_xls_files() 

您不需要手动调用 transaction.set_autocommit() 和类似的低级方法, 除非您有非常具体的需求并且“正常”的交易处理是不够的。