How to use Django model inheritance with signals?

前端 未结 8 784
无人共我
无人共我 2020-12-23 11:15

I have a few model inheritance levels in Django:

class WorkAttachment(models.Model):
    \"\"\" Abstract class that holds all fields that are required in eac         


        
8条回答
  •  甜味超标
    2020-12-23 11:58

    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.apps
    
    class 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 result
    
    def 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).

提交回复
热议问题