如何添加两个值并使用post_save信号保存它们

时间:2017-03-23 11:41:46

标签: python django

我在models.py中使用信号但是当我做一个总和时,这个函数会做两次而不仅仅是一次总和

models.py:

class Articulo(models.Model):
cod_experto = models.CharField(max_length=999, primary_key=True, blank=True)
nombre      = models.CharField(max_length=999, blank=True)
descripcion = models.CharField(max_length=999, blank=True, null=True)
on_delete=models.CASCADE)
stock       = models.IntegerField(blank=True, default=0)
total_pedido =models.IntegerField(blank=True, default=0)

class Pedido(models.Model):
especialidad   = models.ForeignKey('Especialidad')
articulo       = models.ForeignKey('Articulo')
blank=True)
cantidad       = models.IntegerField(blank=True)    default='pendiente')

 def __str__(self):
return '{}'.format(self.especialidad, self.articulo, self.cantidad,   self.estado)

def update_total(sender, instance, **kwargs):
   instance.articulo.total_pedido += instance.cantidad
   instance.articulo.save()

# register the signal
signals.post_save.connect(update_total,sender=Pedido, dispatch_uid="update_stock_count")

views.py

def Cant_ingresar(request, id_pedido, id_especialidad):
especialidad = Especialidad.objects.get(id=id_especialidad)
pedido = Pedido.objects.get(id=id_pedido)
if request.method == 'GET':
  form = PedidoEditForm(instance=pedido)
else:
  form = PedidoEditForm(request.POST, instance=pedido)
  if form.is_valid():
       form.save()
       """
       pedido.estado = 'pendiente'
       pedido.fecha_pedido = datetime.date.today()
       pedido.save()
       especialidad.estado='pendiente'
       especialidad.save()
       """
  return HttpResponseRedirect('/solicitar/lista_active/%s/' % id_especialidad)
return render(request, 'form.html', {'form':form, 'pedido':pedido, 'especialidad':especialidad, 'pedido':pedido}) 

正如你所看到的,我首先保存了在views.py的def中输入的cantidad,然后在模型中用post_save捕获的信号量和与Articulo模型的total_pedido相加,这没有问题,但是添加了两倍相同的数量即,输入3,这将变为total_pedido为6。

2 个答案:

答案 0 :(得分:0)

假设当前注释掉的代码没有被注释掉时会发生这种双重更新:

save

所以你不必惊讶于你的信号处理程序被调用了两次。

有一些解决方案可以避免这种双commit=False次调用(例如将form.save()传递给pedido.save())或(如itzmeontv建议的那样)将此更新从post_save信号移至{{1} } - 但这不会修复潜在的逻辑漏洞:这个代码将被执行每次 Pedido.save()都会被调用(比如更新另一个)不相关的字段),每次将self.cantidad一遍又一遍地添加到self.articulo.total_pedido

这里有两个解决方案:当您知道需要时,明确更新self.articulo(但这可能不太可靠),或者不是盲目地添加到articulo.total_pedido要求articulo从头开始完全重新计算其值,即:

from django.db.models import Sum

class Articulo(models.Model):
   # ....

   def update_total_pedido(self):
       result = self.pedido_set.aggregate(total=Sum('cantidad'))
       self.total_articulo = result['total']
       self.save(update_fields=['total_articulo'])

然后在Pedido

from django.db import transaction

class Pedido(models.Model):
    # ...
    def save(self, *args, **kw):
        with transaction.atomic():
            super(Pedido, self).save(*args, **kw)
            self.articulo.update_total_pedido()

另请注意,如果没有任何内容可以阻止Pedido被删除,您也可以在删除时调用Articulo.update_total_pedido()

答案 1 :(得分:-1)

取代post_save覆盖save

class Pedido(models.Model):
    .....

    def save(self, *args, **kwargs):
        self.articulo.total_pedido += self.cantidad
        self.articulo.save()
        super(Pedido, self).save(*args, **kwargs)