How to Use Signals in Django: Simple Guide with Examples
In Django,
signals let you run code automatically when certain actions happen, like saving a model. You connect a receiver function to a signal using the @receiver decorator or signal.connect(), so your code runs when the event occurs.Syntax
Django signals use a signal object and a receiver function that listens for that signal. You connect them with the @receiver decorator or signal.connect(). The receiver function must accept sender, instance, and **kwargs parameters.
- signal: The event to listen for (e.g.,
post_save). - receiver: The function that runs when the signal fires.
- sender: The model or class sending the signal.
python
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 created: {instance}")
Example
This example shows how to print a message whenever a new Book model instance is created using the post_save signal.
python
from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver 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 signal or receiver causes the handler not to run.
- Not connecting the signal properly (missing
senderor wrong signal) means your code won't trigger. - Placing signal handlers in files that are not imported on startup prevents them from registering.
- Using signals for complex logic can make debugging harder; prefer explicit calls when possible.
python
from django.db.models.signals import post_save from django.dispatch import receiver from myapp.models import MyModel # Wrong: Not specifying sender, so handler runs for all models @receiver(post_save) def handler(sender, instance, **kwargs): print("This runs for every model save, which may be unintended.") # Right: Specify sender to limit to one model @receiver(post_save, sender=MyModel) def handler(sender, instance, **kwargs): print("Runs only when MyModel is saved.")
Quick Reference
Remember these key points when using Django signals:
- Use
@receiver(signal, sender=Model)to connect handlers. - Handler functions must accept
sender,instance, and**kwargs. - Common signals:
pre_save,post_save,pre_delete,post_delete. - Import signal handlers in
apps.pyorready()method to ensure registration.
Key Takeaways
Connect a receiver function to a Django signal using @receiver or signal.connect().
Receiver functions must accept sender, instance, and **kwargs parameters.
Signals run automatically on events like model save or delete to trigger custom code.
Always import and register signal handlers properly to ensure they work.
Avoid complex logic in signals to keep code easier to debug and maintain.