How to use Django model inheritance with signals?
You could register the connection handler without sender
specified. And filter the needed models inside it.
from django.db.models.signals import post_savefrom django.dispatch import receiver@receiver(post_save)def my_handler(sender, **kwargs): # Returns false if 'sender' is NOT a subclass of AbstractModel if not issubclass(sender, AbstractModel): return ...
Ref: https://groups.google.com/d/msg/django-users/E_u9pHIkiI0/YgzA1p8XaSMJ
The simplest solution is to not restrict on the sender
, but to check in the signal handler whether the respective instance is a subclass:
@receiver(post_save)def update_attachment_count_on_save(sender, instance, **kwargs): if isinstance(instance, WorkAttachment): ...
However, this may incur a significant performance overhead as every time any model is saved, the above function is called.
I think I've found the most Django-way of doing this: Recent versions of Django suggest to connect signal handlers in a file called signals.py
. Here's the necessary wiring code:
your_app/__init__.py:
default_app_config = 'your_app.apps.YourAppConfig'
your_app/apps.py:
import django.appsclass YourAppConfig(django.apps.AppConfig): name = 'your_app' def ready(self): import your_app.signals
your_app/signals.py:
def get_subclasses(cls): result = [cls] classes_to_inspect = [cls] while classes_to_inspect: class_to_inspect = classes_to_inspect.pop() for subclass in class_to_inspect.__subclasses__(): if subclass not in result: result.append(subclass) classes_to_inspect.append(subclass) return resultdef update_attachment_count_on_save(sender, instance, **kwargs): instance.work.attachment_count += 1 instance.work.save()for subclass in get_subclasses(WorkAttachment): post_save.connect(update_attachment_count_on_save, subclass)
I think this works for all subclasses, because they will all be loaded by the time YourAppConfig.ready
is called (and thus signals
is imported).
You could try something like:
model_classes = [WorkAttachment, WorkAttachmentFileBased, WorkAttachmentPicture, ...]def update_attachment_count_on_save(sender, instance, **kwargs): instance.work.attachment_count += 1 instance.work.save()for model_class in model_classes: post_save.connect(update_attachment_count_on_save, sender=model_class, dispatch_uid="att_post_save_"+model_class.__name__)
(Disclaimer: I have not tested the above)