Built-in Signals in Django
Introduction
Django's signal dispatching allows decoupled applications to get notified when certain events occur. In this tutorial, we will cover the built-in signals provided by Django, explaining their usage with detailed examples.
What are Signals?
Signals are used to allow certain senders to notify a set of receivers when some action has taken place. They are especially useful in a decoupled architecture, where different parts of the application need to communicate with each other without being tightly coupled.
Connecting to Signals
To connect to a signal, you use the signal.connect()
method. Here is the general pattern:
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(post_save, sender=MyModel)
def my_handler(sender, instance, created, **kwargs):
if created:
print(f"New instance of {sender} created: {instance}")
Built-in Signals
Django provides several built-in signals that we can connect to. Let's look at some of the most commonly used ones:
Model Signals
Model signals are related to the lifecycle of model instances. Some of the key model signals are:
pre_save
Sent before a model's save()
method is called.
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(pre_save, sender=MyModel)
def pre_save_handler(sender, instance, **kwargs):
print(f"About to save: {instance}")
post_save
Sent after a model's save()
method is called.
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(post_save, sender=MyModel)
def post_save_handler(sender, instance, created, **kwargs):
if created:
print(f"New instance created: {instance}")
else:
print(f"Updated instance: {instance}")
pre_delete
Sent before a model's delete()
method is called.
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(pre_delete, sender=MyModel)
def pre_delete_handler(sender, instance, **kwargs):
print(f"About to delete: {instance}")
post_delete
Sent after a model's delete()
method is called.
from django.db.models.signals import post_delete
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(post_delete, sender=MyModel)
def post_delete_handler(sender, instance, **kwargs):
print(f"Deleted: {instance}")
Request/Response Signals
These signals are related to the request/response cycle.
request_started
Sent when Django starts processing an HTTP request.
from django.core.signals import request_started
from django.dispatch import receiver
@receiver(request_started)
def request_started_handler(sender, environ, **kwargs):
print("Request started!")
request_finished
Sent when Django finishes processing an HTTP request.
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished)
def request_finished_handler(sender, **kwargs):
print("Request finished!")
got_request_exception
Sent when an exception is raised while processing an HTTP request.
from django.core.signals import got_request_exception
from django.dispatch import receiver
@receiver(got_request_exception)
def got_request_exception_handler(sender, request, **kwargs):
print("Exception occurred during request!")
Management Signals
These signals are related to Django's management commands.
pre_migrate
Sent before the migrate command runs.
from django.db.models.signals import pre_migrate
from django.dispatch import receiver
@receiver(pre_migrate)
def pre_migrate_handler(sender, app_config, **kwargs):
print("Before migrate command runs!")
post_migrate
Sent after the migrate command runs.
from django.db.models.signals import post_migrate
from django.dispatch import receiver
@receiver(post_migrate)
def post_migrate_handler(sender, app_config, **kwargs):
print("After migrate command runs!")
Conclusion
Django's built-in signals provide a powerful way to handle various events in your application. By leveraging these signals, you can create more decoupled and maintainable code. We hope this tutorial has helped you understand how to use built-in signals in Django effectively.