Django - 使用事务原子回滚保存

时间:2016-01-11 20:22:35

标签: python django transactions atomicity django-database

我正在尝试创建一个保存对象的视图,但是如果引发了一些异常,我想要撤消保存。这就是我试过的:

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中。

3 个答案:

答案 0 :(得分:28)

Atomicity Documentation

总而言之,如果您的视图产生没有错误的响应,@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