Search code examples
djangodjango-class-based-viewsdjango-signals

signals post_save called twice after updating data in class base view django


So i've been stack on this problem that everytime I update my stock in orders it called twice for updating I use the class base view built in Django but in models I have a post signal which it removing the stock of the product. I already use the dispatch_uid but it's not working or any solution that I found on internet not working on my problem.

here is my class base view for updating:

class ItemQtyUpdateClassBaseView(UpdateView):
    template_name = 'components/update/item.html'
    form_class = ItemForm

    def get_context_data(self, **kwargs):
        kwargs['context_title'] = 'Update Order Qty'
        return super(ItemQtyUpdateClassBaseView, self).get_context_data(**kwargs)

    def form_valid(self, form):
        try:
            order_item = OrderModel.objects.get(pk = self.kwargs[self.pk_url_kwarg])
            fetch_product = ProductsModel.objects.get(product_name = order_item.product_name)
            print(fetch_product.qty)
            if fetch_product.dough != None:
                if int(fetch_product.dough.qty) <= 0:
                    messages.error(self.request, 'Not enough qty to order.')
                    return self.form_invalid(form)
            if int(fetch_product.qty) <= 0:
                messages.error(self.request, 'Not enough qty to order.')
                return self.form_invalid(form)
            else:
                self.object = form.save()
                messages.success(self.request, 'Successfully update qty.')
        except Exception as e:
            messages.error(self.request, e)
            return self.form_invalid(form)
        return super(ItemQtyUpdateClassBaseView, self).form_valid(form)

    def form_invalid(self, form):
        return super().form_invalid(form)

    def get_queryset(self):
        return OrderModel.objects.filter(pk = self.kwargs[self.pk_url_kwarg])

    def get_success_url(self):
        return reverse_lazy('core:createorder', kwargs = {
            'typeoforder': self.kwargs['typeoforder']
        })

and here is my model with signal post_save:

class OrderModel(models.Model):
    date = models.DateField(auto_now = True)
    invoice_no = models.ForeignKey(InvoiceModel, on_delete = models.CASCADE)
    product_name = models.CharField(max_length = 150, blank = False, null = True)
    price = models.DecimalField(max_digits = 10, decimal_places = 2)
    qty = models.FloatField(default = 1)

    class Meta:
        db_table = 'orders'
        ordering = ['-pk']

@receiver(post_save, sender = OrderModel, dispatch_uid='signals.ordermodel_removeqty')
def removeQty(sender, instance = None, created = False, **kwargs):
    product = ProductsModel.objects.get(product_name = instance.product_name)
    if product.dough != None:
        dough = DoughModel.objects.get(pk = product.dough.pk)
        dough.qty = abs(dough.qty - (product.qty * instance.qty))
        dough.save()
    else:
        product.qty = abs(product.qty - instance.qty)
        product.save()

Solution

  • You are calling save() method two times in form_valid() method :

    1. self.object = form.save()
    2. super(ItemQtyUpdateClassBaseView, self).form_valid(form)

    You have to remove the below line from form_valid() method:

    self.object = form.save()

    See what form_valid(form)(Django Docs) method do:

    Saves the form instance, sets the current object for the view, and redirects to get_success_url().