HI. It’s very easy to track and manage changes of a Model instance using the post_init
signal in Django.
As shown in the code below, I want to achieve the following behavior:
Whenever a product’s category changes, all associated ProductSpecs
objects should be removed.
BTW there isn’t a many-to-many relationship between Product
and ProductSpecs
.
@receiver(post_init , sender=Product)
def set_old_category(sender, instance, **kwargs):
instance.old_category = instance.category
@receiver(post_save, sender=Product)
def reference_product_signal(sender, instance, created, **kwargs):
if instance.category != instance.old_category:
ProductSpecs.objects.filter(product=instance, key__category=instance.old_category).delete()
The provided code do its job, but it generates duplicate queries each time it see a product on a page.
My question is: How can I avoid these duplicate queries?
Don’t use signals for this.
For tracking a change to a model, create a from_db
method in your model to create the copy of the existing values.
On handling the removal of the (unrelated) ProductSpecs, do this in the save method of the model. However, regardless of how you do the delete, you’re going to do an extra query - that’s by design, and it’s nothing to worry about.
1 Like
AMAZING!!!
Thank you very much @KenWhitesell
its very smooth… the working code
@classmethod
def from_db(cls, db, field_names, values):
if len(values) != len(cls._meta.concrete_fields):
values = list(values)
values.reverse()
values = [
values.pop() if f.attname in field_names else DEFERRED
for f in cls._meta.concrete_fields
]
instance = cls(*values)
instance._state.adding = False
instance._state.db = db
instance._loaded_values = dict(
zip(field_names, (value for value in values if value is not DEFERRED))
)
return instance
def save(self, *args, **kwargs):
if not self._state.adding and (
self.category_id != self._loaded_values["category_id"]
):
ProductSpecs.objects.filter(product=self, key__category__id=self._loaded_values["category_id"]).delete()
super(Product, self).save(*args, **kwargs)