Hi all,

There's a discussion ongoing on ticket #18094
(https://code.djangoproject.com/ticket/18094) that has enough potential
back-compat implications that it seems worth getting feedback here.

Currently, when you delete a concrete-inheritance child model instance,
pre_delete and post_delete signals are sent both for the child and
parent models.

In contrast, when you delete a proxy model instance, the pre/post_delete
signals are sent only for the proxy model class, never for the parent
concrete class.

This is problematic. Imagine a reusable tagging app that has a Tag
model, and attaches a pre_delete signal handler for Tag instances. In my
usage of that app, I use my own TagProxy subclass. When I delete a
TagProxy instance, a Tag is in fact deleted, but the app's pre_delete
signal handler never fires. This violates the reasonable assumption that
subclassing doesn't change superclass behavior except where it
explicitly overrides it.

So we'd like to make the obvious fix, which is to fire the
pre/post_delete signals for every superclass of the instance(s) you
delete, regardless of whether they are parents via concrete or proxy
inheritance.

This raises the question of consistency with pre/post_save and
pre/post_init, which are currently both sent only once, for the exact
class being saved/initialized (thus already inconsistent with delete
signals, which are also sent for concrete-inheritance parents). The same
Tag scenario above would apply equally to save and init signals: the
tagging app should be able to assume that if it registers a save or init
signal handler for Tag, it will get called whenever a Tag is saved or
initialized, even if that's happening via a Tag subclass.

So it seems that perhaps we should also fix the save and init signals to
be fired for each superclass. Is this an acceptable change from a
backwards-compatibility perspective? In the common case of registering a
signal handler using "sender=", it should be a clear win: signal
handlers will now execute when you'd expect them to. But in the case of,
say, a generic audit-trail handler that listens for all post_save (no
sender specified), it will now get what could seem like duplicate
signals for inherited models (one for each superclass of the instance
being saved).

Thoughts?

(The other approach that might come to mind for fixing this would be to
move the fix into the signals framework itself, so that it executes
signal handlers registered for signal=Foo anytime a signal is fired for
anything that passes issubclass(Foo), rather than requiring Foo
identity. This is appealing, and would solve the potential "duplicate
signals" problem with a generic receiver, but is a much more invasive
change in the fundamental semantics of the signals framework, so I don't
think it's a realistic option.)

Carl

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to