Python 将django decorator commit_手动替换为非_原子_请求
我有一个Django视图,它导入一个Excel文件,如果出现异常,我希望捕获它们并报告它们,并回滚任何保存。我得到了一个TransactionManagementError,即使我使用了非原子请求装饰器Python 将django decorator commit_手动替换为非_原子_请求,python,django,django-views,Python,Django,Django Views,我有一个Django视图,它导入一个Excel文件,如果出现异常,我希望捕获它们并报告它们,并回滚任何保存。我得到了一个TransactionManagementError,即使我使用了非原子请求装饰器 由于我也在使用登录所需的装饰程序,我想他们可能会相互干扰。首先我颠倒了顺序,然后删除了所需的登录名。没有变化 我尝试在全球范围内禁用自动事务。也许我做得不对,但这不是我想要的解决方案 我删除了有问题的代码行(见下文),但在尝试回滚时发生了相同的错误 它使用最新的Django和SQLlite在Py
@transaction.non_原子请求
@需要登录(登录url='/accounts/login/?next=/finance/gl\u upload/)
def gl_上传(请求):
事务。设置自动提交(错误)
如果upriv(request.user,['admin','finance'])=='admin':
如果request.method==“POST”:
... 文件处理在这里。。。
例外情况除外,如e:
errs.append(格式({0}\n'行的异常“{1}”)。格式(p['rownum'],e)))
如果出现错误:
事务。回滚()
行\u已删除=0
插入的行数=0
打印(“”.join('Error:{0}\n'。errs中e的格式(e))
其他:
commit()事务
行\u deleted=Gldata.objects.filter(item='Actual',period\u gte=older,period\u lte=newest).delete()
行\u inserted=Gldata.objects.filter(item=temp\u item.update(item='Actual'))
事务。设置自动提交(True)
打印('Deleted:{0},inserted:{1}'。格式(rows\u delete,rows\u inserted))
返回呈现(请求,'gl_upload.html',{'inserted':行插入,'removed':行删除,'errors':errs})
其他:
返回呈现(请求'gl_upload.html',{'form':form})
其他:
form=uploadForm()
返回呈现(请求'gl_upload.html',{'form':form})
我在set_autocommit上收到一个TransactionManagementError,指示一个原子块处于活动状态,尽管我知道装饰程序会禁用它。几年前,我使用了旧的commit_手动装饰器,效果很好
文件“C:\Users\csullivan\responsive\finance\views.py”,第25行,gl\U上传
事务。设置自动提交(错误)
文件“C:\Users\csullivan\responsive\env\lib\site packages\django\db\transaction.py”,第30行,在set\u autocommit中
返回获取连接(使用)。设置自动提交(自动提交)
文件“C:\Users\csullivan\responsive\env\lib\site packages\django\db\backends\base\base.py”,第394行,在set\u autocommit中
self.validate\u no\u原子块()
文件“C:\Users\csullivan\responsive\env\lib\site packages\django\db\backends\base\base.py”,第433行,在validate\u no\u atomic\u块中
“当“原子”块处于活动状态时,这是禁止的。”)
django.db.transaction.TransactionManagementError:当“原子”块处于活动状态时,这是禁止的。我认为
decorator/contextmanager提供了您所需要的内容
--如果底层代码成功并回滚,它将提交事务
当出现异常时
所以在你的情况下,我会:
with atomic():
process_xls_files()
您不需要手动调用transaction.set_autocommit()
和类似的低级方法,
除非您有非常特殊的需求,而且“正常”的事务处理是不够的。谢谢Tomasz。原子是视图的默认设置,不是吗?我希望视图读取整个文件并跟踪它发现的错误(如果有)。如果没有错误,那么我想提交插入,如果有错误,我想回滚并在响应中包括错误列表。我不想将整个文件读入内存,然后进行一次大批量创建,这是另一种方法。由于此文件有50K行,而另一个类似的练习将有120K行。@除非使用
ATOMIC\u REQUESTS=True
设置,否则默认为Deepstop Autocommit。根据您所说的,使用atomic()的:
方法将完全满足您的需要--DB事务将“累积”所有插入的数据,如果没有错误,则在原子块退出时将提交这些数据。如果出现错误,整个事务都将回滚。顺便说一句,即使您设置了ATOMIC\u REQUESTS=True
,ATOMIC()(主要区别在于,提交的保存点仍然可以回滚,例如,当整个事务回滚时)。这有点复杂,但它可以工作。整个处理循环在with块中,在循环结束时,如果填充了错误列表,我只会引发一个通用异常,并在with块外捕获它。虽然我不得不说我更喜欢显式提交和回滚,但感谢您为我指出了一个可行的解决方案!@Deepstop我是gla我想说,与atomic()
的“魔力”相比,手动管理事务要复杂得多
是因为它总是做正确的事情,因此很难意外地引入错误。而手动方式很容易出错,因为您需要覆盖每个可能的场景。此外,多个嵌套的原子()
块正确交互,最外层处理事务,内部处理保存点(s) 。