Correct way of transaction.rollback() with raise exception in django

21,092

Solution 1

In this case - remove decorator, you can wrap part of code in your view:

try:
    with transaction.atomic():
        # ...
        if mal != '':
            raise IntegrityError

except IntegrityError:
    handle_exception()

Any operations attempted inside atomic will already have been rolled back safely when handle_exception() is called.

https://docs.djangoproject.com/en/dev/topics/db/transactions/#django.db.transaction.atomic

Solution 2

I have configured my db to 'ATOMIC_REQUESTS', so each request is also nested in a transaction.

I was looking for a way to rollback without raising an exception. I know, that's not the original question, but for the record the following worked (django 1.11):

from django.db import transaction

def my_view(request):
    # some db interactions
    if it_hit_the_fan:
        transaction.set_rollback(True)
    # return response
Share:
21,092
Alex Lord Mordor
Author by

Alex Lord Mordor

Updated on August 22, 2020

Comments

  • Alex Lord Mordor
    Alex Lord Mordor almost 4 years

    I am working with Django 1.7.1 and python 2.7, I am doing some POST requests that requires to be inside a transaction, actually I am using @transaction.atomic() decorator that makes the entire function to be inside a transaction.

    As far as I know, this decorator is similar to commit_on_success and makes a rollback if a database error is raised.

    Is it possible to raise a custom exception that makes the transaction to rollback but not using save points? I want to return a HttpResponse when the rollback is done, explaining why the transaction was not completed.

    I have this.

    @transaction.atomic()
    def salida_de_almacen(request):
        if request.method == 'POST':
            try:
                folio = request.POST['folio'] #Folio de la orden
                epccoma = request.POST['epc'] #EPCs separados por coma
                if folio is None or epccoma is None:
                    return HttpResponse('Datos Incompletos',status=400)
                detalles = ODetalle.objects.filter(orden__folio=folio)
                epcs = epccoma.replace(' ','').split(',')
                inventario = Inventario.objects.filter(epc__in=epcs)
                mal = '' # Items incompletos
                for d in detalles:
                    for i in inventario:
                        if i.producto.item == d.producto.item:
                            d.cantidad_entregada+=i.cantidad                        
                            i.delete()
                    if d.cantidad_entregada<d.cantidad_ordenada:
                        mal+='%s,' % d.producto.item
                if mal != '':
    
             >>>>   #raise Exception??  <<<<---- I WANT TO RISE AN EXCEPTION HERE TO ROLLBACK THE TR. 
    
                    return HttpResponse('Items Incompletos: '+mal,status=400)
                for d in detalles:
                    d.status=2 #Status completo
                    d.save()
                return HttpResponse(serial_folio,status=200) # Todo bien
            except Exception as e:
                return  HttpResponse(e.message,status=500)    
        else:
            ...