| 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: |