我正在从 Django 1.5 迁移到 Django 1.10,发现数据库事务完全不同,几乎没有提交和回滚控制。
我想要什么:
Perform series of queries in view: my_function(request)
If all queries succeed:
commit
if any query fails:
rollback
insert into log table and commit the insertion
在 Django 1.5 中,我使用回滚并在异常中间件中提交来处理这个问题:
class ExceptionMiddleware(object):
def process_exception(self, request, exception):
# do rollback
# insert into log table
# commit
如何在似乎没有办法进行回滚的 Django 1.10 中实现这一点?
我的 1.10 设置:
AUTOCOMMIT = True
ATOMIC_REQUESTS = True
这会将所有查询放入单个事务中,该事务仅在完成时正确提交。
我会有更多的回滚/提交控制"AUTOCOMMIT = False",但Django建议不要这样做:"这最好用于你想要运行自己的事务控制中间件或做一些非常奇怪的事情的情况。
Django 1.10 还引入了一种新的中间件风格,这使得这变得非常简单:
from django.db import transaction
class LoggingMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
try:
with transaction.atomic():
response = self.get_response(request)
except:
log_failure()
raise
return response
当异常通过transaction.atomic()
的__exit__
方法传播时,事务会自动回滚。然后,您可以捕获异常并在封装视图的主事务之外记录故障。
以下方法有效。当 my_view() 中存在异常时,将回滚其插入,但提交异常中间件中的插入操作。
settings.py
Database ATOMIC_REQUESTS = True
MIDDLEWARE = [
...
'myproject.middleware.ExceptionMiddleware', # put it last
]
views.py
def my_view(request):
do table insertion insertion..
x = 1/0 # cause exception
middleware.py
from django.utils.deprecation import MiddlewareMixin
class ExceptionMiddleware(MiddlewareMixin):
def process_exception(self, request, exception):
# can be put inside "with transaction.atomic():" for more control of rollback/commit within this function
log_error() # do table insertion
# can return some response