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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34730385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 15:26:17  来源:igfitidea点击:

Django - Rollback save with transaction atomic

pythondjangotransactionsatomicitydjango-database

提问by Gocht

I am trying to create a view where I save an object but I'd like to undothat save if some exception is raised. This is what I tried:

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

class MyView(View):

    @transaction.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 undone
                # What am I missing?

        except exception.NotAcceptable, e:
            # do something

What am I doing wrong? even when the exception is raised some_objectis still in Database.

我究竟做错了什么?即使引发异常some_object仍然在数据库中。

采纳答案by jlucier

Atomicity Documentation

原子性文档

To summarize, @transaction.atomicwill execute a transaction on the database if your view produces a response without errors. Because you're catching the exception yourself, it appears to Django that your view executed just fine.

总而言之,@transaction.atomic如果您的视图产生一个没有错误的响应,将在数据库上执行一个事务。因为您自己捕获异常,所以在 Django 看来,您的视图执行得很好。

If you catch the exception, you need to handle it yourself: Controlling Transactions

如果捕获异常,则需要自己处理:控制事务

If you need to produce a proper json response in the event of failure:

如果您需要在失败时生成正确的 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()

回答by jpic

However, if an exception happens in a function decorated with transaction.atomic, then you don't have anything to do, it'll rollback automatically to the savepoint created by the decorator before running the your function, as documented:

但是,如果在使用 transaction.atomic 装饰的函数中发生异常,那么您无事可做,它会在运行您的函数之前自动回滚到装饰器创建的保存点,如文档所述

atomic allows us to create a block of code within which the atomicity on the database is guaranteed. If the block of code is successfully completed, the changes are committed to the database. If there is an exception, the changes are rolled back.

atomic 允许我们创建一个代码块,在其中保证数据库的原子性。如果代码块成功完成,更改将提交到数据库。如果出现异常,则回滚更改。

If the exception is catched in an except block, then it should be re-raised for atomic to catch it and do the rollback, ie.:

如果异常在一个 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

Also, if you want more control, you can rollback manually to previously set savepoint, ie.:

此外,如果您想要更多控制,您可以手动回滚到之前设置的 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)

回答by Antonio Cord

For me this works in Django 2.2.5

对我来说,这适用于 Django 2.2.5

First of all in your settings.py

首先在你的settings.py

...

DATABASES = {
    'default': {
        'ENGINE': 'xxx',  # transactional db
        ...
        'ATOMIC_REQUESTS': True,
    }
}

And in your function (views.py)

在你的函数中(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