Django - Rollback save with transaction atomic

后端 未结 3 1857
猫巷女王i
猫巷女王i 2020-12-04 23:29

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

class MyView(         


        
相关标签:
3条回答
  • 2020-12-05 00:02

    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:

    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.

    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.:

        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.:

    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)
    
    0 讨论(0)
  • 2020-12-05 00:06

    Atomicity Documentation

    To summarize, @transaction.atomic will 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.

    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:

    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()
    
    0 讨论(0)
  • 2020-12-05 00:16

    For me this works in Django 2.2.5

    First of all in your settings.py

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

    And in your function (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
    
    0 讨论(0)
提交回复
热议问题