Django Signals

Let's see how you can use signals for decoupled communication between Django apps and register signal handlers for model events:

Using signals for decoupled communication:

Signals make it possible for different parts of Django application to have a common communication without them being linked directly.

Hence, this means that any part of the application can send commands, while others can, in turn, take orders (caused by the command), without necessarily have to call the actual method or function.

Registering signal handlers for model events:

You give signal to handler of specific events for model like pre_save, post_save, pre_delete and post_delete, so that it would trigger whatever given function.

This kind of signal allows you to perform actions along the lines of saving a model instance before or deleting it after another instance.

                                
# signals.py

from django.db.models.signals import pre_save, post_save, pre_delete, post_delete
from django.dispatch import receiver
from .models import MyModel

@receiver(pre_save, sender=MyModel)
def mymodel_pre_save_handler(sender, instance, **kwargs):
    # Perform actions before saving MyModel instance
    pass

@receiver(post_save, sender=MyModel)
def mymodel_post_save_handler(sender, instance, created, **kwargs):
    # Perform actions after saving MyModel instance
    pass

@receiver(pre_delete, sender=MyModel)
def mymodel_pre_delete_handler(sender, instance, **kwargs):
    # Perform actions before deleting MyModel instance
    pass

@receiver(post_delete, sender=MyModel)
def mymodel_post_delete_handler(sender, instance, **kwargs):
    # Perform actions after deleting MyModel instance
    pass

                                
                            

In this example, we define signal handlers using the @receiver decorator, which registers the functions to be called when the specified signals are sent by the MyModel class.

Connecting signals:

To ensure that Django loads your signal handlers, you need to connect them. You can do this in the ready() method of your app configuration class or by importing the signal handlers in your app's __init__.py file.

                                
# apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'

    def ready(self):
        import myapp.signals