我正在尝试创建一个保存对象的视图,但是我想undo在出现异常时进行保存。这是我尝试过的:
class MyView(View):
@transation.atomic
def post(self, request, *args, **kwargs):
try:
some_object = SomeModel(...)
some_object.save()
if something:
raise exception.NotAcceptable()
# When the workflow comes into this condition, I think the previous save should be undome
# Whant am I missing?
except exception.NotAcceptable, e:
# do something
我在做什么错?即使引发异常,some_object
仍在数据库中。
总而言之,如果视图产生没有错误的响应,则@transaction.atomic
将在数据库上执行事务。因为您自己正在捕获异常,所以在Django中,您的视图执行得很好。
如果发现异常,则需要自己处理:Controlling Transactions
如果失败时需要产生适当的json响应:
from django.db import SomeError, transaction
def viewfunc(request):
do_something()
try:
with transaction.atomic():
thing_that_might_fail()
except SomeError:
handle_exception()
render_response()
但是,如果在用transaction.atomic装饰的函数中发生异常,那么您就无事可做,它会以rollback automatically to the savepoint created by the decorator before running the your function的形式显示为documented:
atomic允许我们创建一个代码块,在其中保证数据库的原子性。如果代码块成功完成,则更改将提交给数据库。如果有异常,则更改将回滚。
如果异常被捕获在except块中,则应重新引发它以使atomic捕获并执行回滚,即:
try:
some_object = SomeModel(...)
some_object.save()
if something:
raise exception.NotAcceptable()
# When the workflow comes into this condition, I think the previous save should be undome
# Whant am I missing?
except exception.NotAcceptable, e:
# do something
raise # re-raise the exception to make transaction.atomic rollback
此外,如果需要更多控制权,则可以手动回滚到previously set savepoint,即:
class MyView(View):
def post(self, request, *args, **kwargs):
sid = transaction.savepoint()
some_object = SomeModel(...)
some_object.save()
if something:
transaction.savepoint_rollback(sid)
else:
try:
# In worst case scenario, this might fail too
transaction.savepoint_commit(sid)
except IntegrityError:
transaction.savepoint_rollback(sid)
对我来说,这在Django 2.2.5中有效
首先是您的setting.py
...
DATABASES = {
'default': {
'ENGINE': 'xxx', # transactional db
...
'ATOMIC_REQUESTS': True,
}
}
并且在您的函数中(view.py)
from django.db import transaction
@transaction.atomic
def make_db_stuff():
# do stuff in your db (inserts or whatever)
if success:
return True
else:
transaction.set_rollback(True)
return False