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')