#24738: Possible bug in m2m_changed signal when deleting related objects
-------------------------------------+-------------------------------------
Reporter: No-0n3 | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution: duplicate
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by No-0n3):
Hi again,
I looked at #6707 and it isn't a problem about M2M in admin I'm talking
about. Installed the master branch from github and tested.
My I'm trying to delete all objects from the database that doesn't have
any relation by signaling that the relationship has been changed with the
"m2m_changed" signal.
If I delete a model through the shell with "<object>.delete()", then no
"m2m_changed" signal is sent that any relations has been changed in any
way.
Here is my test:
{{{
Python 2.7.9 (default, Dec 12 2014, 07:23:35)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from blacklist.models import Blacklist, Record
>>> l = Blacklist.objects.create(name="test")
>>> r = Record.objects.create(ip="127.0.0.2")
>>> r.blacklists.add(l)
{'reverse': False, 'signal': <django.db.models.signals.ModelSignal object
at 0x7606ad30>, 'instance': <Record: 127.0.0.2>, 'pk_set': set([10L]),
'using': 'default', 'model': <class 'blacklist.models.Blacklist'>,
'action': u'pre_add'}
{'reverse': False, 'signal': <django.db.models.signals.ModelSignal object
at 0x7606ad30>, 'instance': <Record: 127.0.0.2>, 'pk_set': set([10L]),
'using': 'default', 'model': <class 'blacklist.models.Blacklist'>,
'action': u'post_add'}
>>> Record.objects.all()
[<Record: 127.0.0.1>, <Record: 127.0.0.2>]
>>> Record.objects.all()[0].blacklists.add(l)
{'reverse': False, 'signal': <django.db.models.signals.ModelSignal object
at 0x7606ad30>, 'instance': <Record: 127.0.0.1>, 'pk_set': set([10L]),
'using': 'default', 'model': <class 'blacklist.models.Blacklist'>,
'action': u'pre_add'}
{'reverse': False, 'signal': <django.db.models.signals.ModelSignal object
at 0x7606ad30>, 'instance': <Record: 127.0.0.1>, 'pk_set': set([10L]),
'using': 'default', 'model': <class 'blacklist.models.Blacklist'>,
'action': u'post_add'}
>>> Record.objects.all()
[<Record: 127.0.0.1>, <Record: 127.0.0.2>]
>>> Blacklist.objects.all()
[<Blacklist: test>]
>>> Blacklist.objects.all()[0].record_set.all()
[<Record: 127.0.0.1>, <Record: 127.0.0.2>]
>>> l = Blacklist.objects.all()[0]
>>> l
<Blacklist: test>
>>> l.delete()
>>> Record.objects.all()
[<Record: 127.0.0.1>, <Record: 127.0.0.2>]
>>> Record.objects.all()[0].blacklists.all()
[]
>>>
}}}
The signal receiver function:
{{{
@receiver(m2m_changed, sender=Record.blacklists.through)
def blacklists_changed(sender, **kwargs):
print "%s" % kwargs # Only to see if any data was sent and to see if
an m2m_changed signal was received.
if kwargs['action'] == "post_clear":
if kwargs['reverse']:
Record.objects.annotate(count=Count('blacklists')).exclude(count__gt=0).delete()
}}}
No signal is sent at deletetion of a related object to that changed the
relations by deleting the object. Sorry but it isn't a duplication.
Entire code:
{{{
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):
print "%s" % 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()
}}}
BR / Isaac
--
Ticket URL: <https://code.djangoproject.com/ticket/24738#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/064.c998feda67ca4d63381ddad065ca4c71%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.