[Answered ]-How to make on update record pass the signal in Django Model?

1👍

This is not a bug, this is expected behavior, your if created checks if you run the signal for a created object, hence it will not run in case the record is updated.

You can omit this with:

def ItemGenerator(sender, instance, created, *args, **kwargs):
    if created:
        temp_count = Item.objects.all().count()
        no = str('ITEM') + '/' + str(temp_count)
    else:
        no = instance.code
    gst_cal = instance.price * instance.gsts.gst / 100
    net_amounts = instance.price + gst_cal
    query = Item.objects.filter(pk=instance.pk).update(
        code=no,
        cgst=round(gst_cal / 2),
        sgst=round(gst_cal / 2),
        net_amount=round(net_amounts),
    )

But the signal is not necessary. Signals are often a pattern to avoid. Signals for example don’t run in case of bulk updates or bulk creates, can easily result in infinite recursion, etc. Here is an article I wrote that discusses potential problems with signals.

To make matters worse, this is just data duplication, which means that you repeat the same data, but in another shape or form.

from django.conf import settings


class Item(models.Model):
    status_type = (('a', 'Active'), ('d', 'Deactive'))
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    gsts = models.ForeignKey(Gst, on_delete=models.CASCADE)
    status = models.CharField(max_length=1, choices=status_type, default='a')
    create_at = models.DateField(auto_now_add=True)
    update_at = models.DateField(auto_now=True)
    create_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE
    )

    @property
    def code(self):
        return f'ITEM/{type(self).objects.filter(create_at__lt=self.create_at).count()}'

    @property
    def cgst_unround(self):
        if not hasattr(self, '_cgst'):
            self._cgst = self.price * self.gsts.gsts / 100
        return self._cgst

    @property
    def cgst(self):
        return round(self.cgst_unround, 2)

    @property
    def sgst(self):
        return self.cgst

    @property
    def net_amount(self):
        return round(self.price + self.gst)

    def __str__(self):
        return self.name

This will then determine the values when needed, so we can use some_item.net_amount, and if so, it will fetch the .gsts and do the proper calculations. This will thus also return a different value, if you change the .price or for example the .gst of the .gsts, which is more reliable: if you alter the gst of a Gst object, signals will not run for the Item, although the net_amount depends on that change, by just calculating it when needed, that will not be a problem.

In case you need to determine the .cgst or .sgst for a large amount of objects, it can cause the so-called N+1 problem. We can omit that by selecting the related .gsts of the items before calculating:

Item.objects.select_related('gsts')

Leave a comment