9 | | 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. |
| 9 | Here is my test: |
| 10 | {{{ |
| 11 | Python 2.7.9 (default, Dec 12 2014, 07:23:35) |
| 12 | [GCC 4.9.2] on linux2 |
| 13 | Type "help", "copyright", "credits" or "license" for more information. |
| 14 | (InteractiveConsole) |
| 15 | >>> from blacklist.models import Blacklist, Record |
| 16 | >>> l = Blacklist.objects.create(name="test") |
| 17 | >>> r = Record.objects.create(ip="127.0.0.2") |
| 18 | >>> r.blacklists.add(l) |
| 19 | {'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'} |
| 20 | {'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'} |
| 21 | >>> Record.objects.all() |
| 22 | [<Record: 127.0.0.1>, <Record: 127.0.0.2>] |
| 23 | >>> Record.objects.all()[0].blacklists.add(l) |
| 24 | {'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'} |
| 25 | {'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'} |
| 26 | >>> Record.objects.all() |
| 27 | [<Record: 127.0.0.1>, <Record: 127.0.0.2>] |
| 28 | >>> Blacklist.objects.all() |
| 29 | [<Blacklist: test>] |
| 30 | >>> Blacklist.objects.all()[0].record_set.all() |
| 31 | [<Record: 127.0.0.1>, <Record: 127.0.0.2>] |
| 32 | >>> l = Blacklist.objects.all()[0] |
| 33 | >>> l |
| 34 | <Blacklist: test> |
| 35 | >>> l.delete() |
| 36 | >>> Record.objects.all() |
| 37 | [<Record: 127.0.0.1>, <Record: 127.0.0.2>] |
| 38 | >>> Record.objects.all()[0].blacklists.all() |
| 39 | [] |
| 40 | >>> |
| 41 | }}} |
11 | | Here are my models and signals with my workaround: |
| 43 | The signal receiver function: |
| 44 | {{{ |
| 45 | @receiver(m2m_changed, sender=Record.blacklists.through) |
| 46 | def blacklists_changed(sender, **kwargs): |
| 47 | print "%s" % kwargs # Only to see if any data was sent and to see if an m2m_changed signal was received. |
| 48 | |
| 49 | if kwargs['action'] == "post_clear": |
| 50 | if kwargs['reverse']: |
| 51 | Record.objects.annotate(count=Count('blacklists')).exclude(count__gt=0).delete() |
| 52 | }}} |
| 53 | |
| 54 | No signal is sent at deletion of a related object when the relation was broken by deleting the object. Sorry but it isn't a duplication. Because I don't get any output that the signal function has run as when I ran the "add"-relation function and the related objects are still there without any relation to a object. If I uncomment the second function that catch a "pre_delete" and explicitly call "clear()" on the M2M-field I receive a "m2m_changed" signal and all records without a related object are deleted. According to docs "m2m_changed" was a signal that is sent when the relationship between objects are changed, which happens when the object is deleted. |
| 55 | |
| 56 | Entire code: |