Django - откат с транзакцией Atom

Я пытаюсь создать представление, в котором я сохраняю объект, но я хотел бы отменить его, если будет создано какое-то исключение. Это то, что я пробовал:

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 все еще находится в базе данных.

Ответ 1

Документация по атомности

Подводя итог, @transaction.atomic выполнит транзакцию в базе данных, если ваше представление выдаст ответ без ошибок. Поскольку вы сами выбираете исключение, Django кажется, что ваше представление выполнено просто отлично.

Если вы поймаете исключение, вам нужно самому обработать его: Управление транзакциями

Если вам нужно создать правильный ответ 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()

Ответ 2

Однако, если исключение происходит в функции, украшенной транзакцией .atomic, то вам нечего делать, она будет автоматически откат к сохранить точку, созданную декоратором, перед запуском вашей функции, как документально:

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

Кроме того, если вы хотите получить больше контроля, вы можете вручную отменить команду ранее установленную точку сохранения, то есть.:

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)

Ответ 3

Для меня это работает в 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