我正在尝试创建一个保存对象的视图,但是如果引发了一些异常,我想要撤消保存。这就是我试过的:
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
仍然在DataBase中。
答案 0 :(得分:28)
总而言之,如果您的视图产生没有错误的响应,@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()
答案 1 :(得分:12)
但是,如果在使用transaction.atomic修饰的函数中发生异常,那么您无需执行任何操作,它将rollback automatically to the savepoint created by the decorator before running the your function documented:
atomic允许我们创建一个代码块,在该代码块中保证数据库的原子性。如果代码块成功完成,则更改将提交到数据库。如果存在异常,则会回滚更改。
如果在except块中捕获异常,那么应该重新引发异常以捕获它并执行回滚,即:
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)
答案 2 :(得分:1)
对我来说,这在Django 2.2.5中有效
首先在您的settings.py
...
DATABASES = {
'default': {
'ENGINE': 'xxx', # transactional db
...
'ATOMIC_REQUESTS': True,
}
}
在您的函数中(views.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