【问题标题】:How to add two values and save them with post_save signals如何添加两个值并使用 post_save 信号保存它们
【发布时间】:2017-03-23 11:41:46
【问题描述】:

我在 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中输入的候选人,然后在模型中使用post_save捕获的信号量并与Articulo模型的total_pedido相加,这没有问题,但添加两次相同的金额,即输入 3,total_pedido 为 6。

【问题讨论】:

  • 看看this。这可能是您正在寻找的。​​span>
  • 你的代码格式可以吗?

标签: python django


【解决方案1】:

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

if form.is_valid():
   # this will call `pedido.save()` once
   form.save()
   # ...
   # adds some things to pedido...
   # ...
   # and here you're saving pedido a second time
   pedido.save()

所以毫无疑问,您的信号处理程序被调用了两次。

有一些解决方案可以避免这种双重 save 调用(例如将 commit=False 传递给 form.save())或(如 itzmeontv 建议的)将此更新从 post_save 信号移动到 pedido.save() - 但这赢了'不修复潜在的逻辑缺陷:这段代码将被执行每次 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()

【讨论】:

    【解决方案2】:

    而不是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) 
    

    【讨论】:

    • 我理解你的意思,虽然这个例子并没有给我的 total_pedido 增加任何东西
    • 根据你的回答更新了views.py我想是因为我有不止一个.save()?
    • 我已经试过了!感谢您的回答,我的头脑清醒了,谢谢您,先生!非常感谢!
    • 这仍然会盲目更新self.articulo.total_pedido 每次 Pedido.save() 被调用。
    • @itzmeontv 抱歉,但没有雪茄 - 这里不涉及递归,在信号处理程序中调用的是 Articulo.save(),而不是 Pedido.save()。如果是这种情况,OP 将获得无限递归。
    猜你喜欢
    • 2016-05-18
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 2020-09-28
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多