How to Use the receiver Decorator in Django Signals
In Django, use the
@receiver decorator to connect a function to a signal easily by specifying the signal and optionally the sender. This decorator helps you write clean, readable code for handling events like model saves or deletes.Syntax
The @receiver decorator connects a function to a Django signal. You specify the signal to listen for and optionally the sender (the model or class sending the signal). The decorated function will run when the signal is sent.
@receiver(signal, sender=SenderClass): Decorates the handler function.signal: The Django signal to listen to (e.g.,post_save).sender: Optional. Limits the signal to a specific sender.- The decorated function receives
sender,instance, and other keyword arguments.
python
from django.dispatch import receiver from django.db.models.signals import post_save 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.__name__} created: {instance}")
Example
This example shows how to use the @receiver decorator to print a message whenever a new Book model instance is created.
python
from django.db import models from django.dispatch import receiver from django.db.models.signals import post_save class Book(models.Model): title = models.CharField(max_length=100) @receiver(post_save, sender=Book) def announce_new_book(sender, instance, created, **kwargs): if created: print(f"A new book titled '{instance.title}' was added.")
Output
A new book titled 'Django Basics' was added.
Common Pitfalls
- Forgetting to import the
receiverdecorator or the signal you want to use. - Not specifying the
senderwhen you want to limit the signal to a specific model, causing the handler to run for all senders. - Defining the signal handler function without the correct parameters (
sender,instance, and**kwargs). - Placing signal handlers in files that are not imported on startup, so the signals never connect.
python
from django.dispatch import receiver from django.db.models.signals import post_save from myapp.models import MyModel # Wrong: Missing sender, runs for all models @receiver(post_save) def handler(sender, instance, **kwargs): print("Signal received") # Right: Specify sender to limit scope @receiver(post_save, sender=MyModel) def handler(sender, instance, **kwargs): print(f"Signal from {sender.__name__}")
Quick Reference
Use this quick guide to remember how to use the @receiver decorator:
| Concept | Description |
|---|---|
| @receiver(signal, sender=SenderClass) | Connects a function to a signal, optionally filtering by sender. |
| signal | A Django signal like post_save, pre_delete, etc. |
| sender | Optional model or class sending the signal to filter events. |
| Handler function params | sender, instance, created (if applicable), and **kwargs. |
| Import location | Place signal handlers in apps.py or a signals.py file imported on app startup. |
Key Takeaways
Use the @receiver decorator to cleanly connect functions to Django signals.
Always specify the sender to limit signal handling to a specific model when needed.
Ensure your handler function has the correct parameters to receive signal data.
Place signal handlers in files that are imported when Django starts to activate them.
Common signals include post_save, pre_save, post_delete, and more.