【问题标题】:Correct way of transaction.rollback() with raise exception in django在 django 中引发异常的 transaction.rollback() 的正确方法
【发布时间】:2015-01-11 03:26:34
【问题描述】:

我正在使用 Django 1.7.1 和 python 2.7,我正在做一些需要在事务中的 POST 请求,实际上我正在使用 @transaction.atomic() 装饰器,它使整个函数都在事务中。

据我所知,这个装饰器类似于commit_on_success,如果引发数据库错误,则会回滚。

是否可以引发自定义异常,使事务回滚但不使用保存点?我想在回滚完成后返回一个 HttpResponse,解释为什么事务没有完成。

我有这个。

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

【问题讨论】:

    标签: python django exception-handling transactions


    【解决方案1】:

    在这种情况下 - 移除装饰器,您可以在视图中包装部分代码:

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

    atomic 内尝试的任何操作都将在调用 handle_exception() 时安全回滚。

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

    【讨论】:

    • 非常好,它可以工作,但是,这是唯一可以使事务回滚的例外吗?我可以自己做一个例外并在except 中放入handle_exception() 以成功回滚吗?
    • same link - docs "DatabaseError 及其子类,例如 IntegrityError。发生此类错误后,事务将中断,Django 将在原子块末尾执行回滚。"
    • 如果您想手动处理使用 - sid = transaction.savepoint()transaction.savepoint_commit(sid) ... 无论如何,请阅读整个文档页面,它会很清楚
    • 在 Python 3.7.3 和 Django 2.2.2 上确认事务也会为 ValueError() 回滚。我认为任何异常都会导致这种情况,而不仅仅是 DatabaseError。来自同一个参考文档:“退出原子块时,Django 查看它是正常退出还是异常退出,以确定是提交还是回滚。如果您在原子块内捕获并处理异常,您可以对 Django 隐藏事实上发生了问题。这可能会导致意外行为。"
    • @Guilherme 如果你没有捕捉到 IntegrityError 那么简单——是的,它会起作用
    【解决方案2】:

    我已将我的数据库配置为'ATOMIC_REQUESTS',因此每个请求也嵌套在一个事务中。

    我正在寻找一种方法来回滚而不引发异常。我知道,这不是最初的问题,但作为记录,以下工作(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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 2018-09-13
      • 1970-01-01
      相关资源
      最近更新 更多