I have a signal callback in django:
@receiver(post_save, sender=MediumCategory)
def update_category_descendants(sender, **kwargs):
def children_for(category):
return MediumCategory.objects.filter(parent=category)
def do_update_descendants(category):
children = children_for(category)
descendants = list() + list(children)
for descendants_part in [do_update_descendants(child) for child in children]:
descendants += descendants_part
category.descendants.clear()
for descendant in descendants:
if category and not (descendant in category.descendants.all()):
category.descendants.add(descendant)
category.save()
return list(descendants)
# call it for update
do_update_descendants(None)
but in the function body I'm using .save()
on models MediumCategory
that couses that the signal is dispatched again. How can I disable it; the perfect solution would be a with
statement with some 'magic' inside.
UPDATE: That's final solution, if anyone interested.
class MediumCategory(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(blank=True)
parent = models.ForeignKey('self', blank=True, null=True)
parameters = models.ManyToManyField(AdvertisementDescriptonParameter, blank=True)
count_mediums = models.PositiveIntegerField(default=0)
count_ads = models.PositiveIntegerField(default=0)
descendants = models.ManyToManyField('self', blank=True, null=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(MediumCategory, self).save(*args, **kwargs)
def __unicode__(self):
return unicode(self.name)
(...)
@receiver(post_save, sender=MediumCategory)
def update_category_descendants(sender=None, **kwargs):
def children_for(category):
return MediumCategory.objects.filter(parent=category)
def do_update_descendants(category):
children = children_for(category)
descendants = list() + list(children)
for descendants_part in [do_update_descendants(child) for child in children]:
descendants += descendants_part
if category:
category.descendants.clear()
for descendant in descendants:
category.descendants.add(descendant)
return list(descendants)
# call it for update
do_update_descendants(None)
@danihp disconnecting a signal is not a DRY and consistent solution, such as using update() instead of save().
To disable a signal on your model, a simple way to go is to set an attribute on the current instance to prevent upcoming signals firing.
This can be done using a simple decorator that checks if the given instance has the 'skip_signal' attribute, and if so prevents the method from being called:
You can now use it this way:
Hope This helps.
Perhaps I'm wrong, but I think that
category.save()
is not needed in your code, add() is enough because change is made in descendant but in category.Also, to avoid signals you can:
Descendant.objects.filter( pk = descendant.pk ).update( category = category )