#18094: `pre_delete` and `post_delete` signals are not correctly sent in inheritance scenarios involving proxy models -------------------------------------+------------------------------------- Reporter: charettes | Owner: nobody Type: Bug | Status: new Component: Database layer | Version: 1.4 (models, ORM) | Keywords: model proxy multi-table Severity: Normal | inheritance signals delete Triage Stage: Unreviewed | Has patch: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- This is a follow up of #18083.
Given the following models and signals (as of r17887): {{{#!python from django.db import models from django.db.models import signals class A(models.Model): pass class AProxy(A): class Meta: proxy = True class B(A): pass class BFirstProxy(B): class Meta: proxy = True class BSecondProxy(B): class Meta: proxy = True class BFirstProxyFirstProxy(BFirstProxy): class Meta: proxy = True class BFirstProxySecondProxy(BFirstProxy): class Meta: proxy = True def pre_delete(sender, instance, **kwargs): print "`pre_delete` %r %r" % (sender, instance) signals.pre_delete.connect(pre_delete, A) signals.pre_delete.connect(pre_delete, AProxy) signals.pre_delete.connect(pre_delete, B) signals.pre_delete.connect(pre_delete, BFirstProxy) signals.pre_delete.connect(pre_delete, BSecondProxy) signals.pre_delete.connect(pre_delete, BFirstProxyFirstProxy) signals.pre_delete.connect(pre_delete, BFirstProxySecondProxy) def post_delete(sender, instance, **kwargs): return # Avoid dispatching for output clarity print "`post_delete` %r %r" % (sender, instance) signals.post_delete.connect(post_delete, A) signals.post_delete.connect(post_delete, AProxy) signals.post_delete.connect(post_delete, B) signals.post_delete.connect(post_delete, BFirstProxy) signals.post_delete.connect(post_delete, BSecondProxy) signals.post_delete.connect(post_delete, BFirstProxyFirstProxy) signals.post_delete.connect(post_delete, BFirstProxySecondProxy) }}} `pre_delete` and `post_delete` signals dispatching depends on the deletion source and don't propagate up the proxy chain nor to the proxy leaves. i.e. (here `post_delete`'s dispatching should behave the same) == Basic model proxy == '''Actual behaviours''' {{{ >>> A.objects.create().delete() `pre_delete` <class 'proxy_signals.models.A'> <A: A object> >>> AProxy.objects.create().delete() `pre_delete` <class 'proxy_signals.models.AProxy'> <AProxy: AProxy object> }}} '''Expected behaviour in both cases''' {{{ `pre_delete` <class 'proxy_signals.models.AProxy'> <AProxy: AProxy object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> }}} == Multi-table inheritance model proxy == '''Actual behaviours''' {{{ >>> B.objects.create().delete() `pre_delete` <class 'proxy_signals.models.B'> <B: B object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> >>> BFirstProxy.objects.create().delete() `pre_delete` <class 'proxy_signals.models.BFirstProxy'> <BFirstProxy: BFirstProxy object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> >>> BSecondProxy.objects.create().delete() `pre_delete` <class 'proxy_signals.models.BSecondProxy'> <BSecondProxy: BSecondProxy object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> >>> BFirstProxyFirstProxy.objects.create().delete() `pre_delete` <class 'proxy_signals.models.BFirstProxyFirstProxy'> <BFirstProxyFirstProxy: BFirstProxyFirstProxy object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> >>> BFirstProxySecondProxy.objects.create().delete() `pre_delete` <class 'proxy_signals.models.BFirstProxySecondProxy'> <BFirstProxySecondProxy: BFirstProxySecondProxy object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> }}} '''Expected behaviour in all cases''' {{{ `pre_delete` <class 'proxy_signals.models.BFirstProxyFirstProxy'> <BFirstProxyFirstProxy: BFirstProxyFirstProxy object> `pre_delete` <class 'proxy_signals.models.BFirstProxySecondProxy'> <BFirstProxySecondProxy: BFirstProxySecondProxy object> `pre_delete` <class 'proxy_signals.models.BFirstProxy'> <BFirstProxy: BFirstProxy object> `pre_delete` <class 'proxy_signals.models.BSecondProxy'> <BSecondProxy: BSecondProxy object> `pre_delete` <class 'proxy_signals.models.B'> <B: B object> `pre_delete` <class 'proxy_signals.models.AProxy'> <AProxy: AProxy object> `pre_delete` <class 'proxy_signals.models.A'> <A: A object> }}} What needs to be fixed: * Dispatch the `concrete_model` signals even when the source is an instance of a proxy * Dispatch the signals for all proxy of concrete models involved in the deletion * Preserve the expected dispatching order Failing integrated TestCase to come. -- Ticket URL: <https://code.djangoproject.com/ticket/18094> 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 post to this group, send email to django-updates@googlegroups.com. To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-updates?hl=en.