Opened 10 years ago
Last modified 10 years ago
#24738 closed Bug
Possible bug in m2m_changed signal when deleting related objects — at Initial Version
Reported by: | No-0n3 | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | No-0n3 | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hi,
Have observed that no m2m_changed signal is sent when a related object is deleted.
If I explicitly clear the relations with "clear()" or remove the relation with "remove()", m2m_changed is correctly sent but if I delete it without calling "clear()" or "remove()" on the m2m field no signal is sent to indicate a change in relationship.
Is this by design or should a m2m_changed signal be sent when a related object is deleted from the m2m table at deletion when the relations also are removed.
Right now I've done a workaround by catching the "pre_delete" signal on my model that explicitly calls "clear()" on the M2M field to trigger the signal and catching it with my other signal function when it gets a "post_clear" action in m2m_changed signal.
Here are my models and signals with my workaround:
from django.db import models from django.db.models.signals import m2m_changed, pre_delete from django.dispatch import receiver from django.db.models import Count # Models class Type(models.Model): name = models.CharField(max_length=200) def __unicode__(self): return unicode(self.name) class Blacklist(models.Model): source = models.URLField() name = models.CharField(max_length=200) date_added = models.DateField(auto_now_add=True) last_update = models.DateField(auto_now=True) types = models.ManyToManyField(Type) def __unicode__(self): return unicode(self.name) class Record(models.Model): blacklists = models.ManyToManyField(Blacklist) ip = models.GenericIPAddressField(protocol='IPv4', unique=True) def __unicode__(self): return unicode(self.ip) # Signal actions @receiver(m2m_changed, sender=Record.blacklists.through) def blacklists_changed(sender, **kwargs): if kwargs['action'] == "post_clear": if kwargs['reverse']: Record.objects.annotate(count=Count('blacklists')).exclude(count__gt=0).delete() @receiver(pre_delete, sender=Blacklist) def blacklist_deleted(sender, **kwargs): kwargs['instance'].record_set.clear()
If you comment out the blacklist_deleted and do a <Blacklist instance>.delete() no m2m_changed signal is sent at all.
BR / Isaac