Connecting signal handlers lets your Django app react automatically when certain actions happen, like saving a record. It helps keep your code organized and responsive.
Connecting signal handlers in Django
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Django
from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=YourModel) def your_handler(sender, instance, created, **kwargs): if created: # code to run after a new instance is saved pass
The @receiver decorator connects your function to a signal.
The sender argument specifies which model triggers the signal.
Examples
Django
from django.db.models.signals import post_save from django.dispatch import receiver from myapp.models import User @receiver(post_save, sender=User) def send_welcome_email(sender, instance, created, **kwargs): if created: print(f"Welcome email sent to {instance.email}")
Django
from django.db.models.signals import pre_delete from django.dispatch import receiver from myapp.models import Article @receiver(pre_delete, sender=Article) def log_article_deletion(sender, instance, **kwargs): print(f"Article titled '{instance.title}' is about to be deleted.")
Sample Program
This code defines a Product model and connects a signal handler to post_save. When a product is saved, if its stock is less than 5, it prints a warning message.
Django
from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver class Product(models.Model): name = models.CharField(max_length=100) stock = models.IntegerField(default=0) @receiver(post_save, sender=Product) def notify_low_stock(sender, instance, **kwargs): if instance.stock < 5: print(f"Warning: Low stock for product '{instance.name}'") # Simulate saving products p1 = Product(name='Pen', stock=10) p1.save() p2 = Product(name='Notebook', stock=3) p2.save()
Important Notes
Signals run synchronously by default, so avoid long tasks inside handlers.
Always specify the sender to avoid handling signals from unrelated models.
Summary
Signals let your app react automatically to model events.
Use @receiver to connect handlers to signals.
Check the created flag to run code only on new records.
Practice
1. What is the main purpose of connecting signal handlers in Django?
easy
Solution
Step 1: Understand signal handlers
Signal handlers let Django apps respond automatically to events like saving or deleting a model.Step 2: Identify the purpose
Connecting signal handlers means running code automatically when these events happen, without manual calls.Final Answer:
To automatically run code when certain model events happen -> Option DQuick Check:
Signal handlers = automatic event response [OK]
Hint: Signals run code automatically on model events [OK]
Common Mistakes:
- Thinking signals create database tables
- Confusing signals with manual function calls
- Assuming signals style templates
2. Which of the following is the correct way to connect a signal handler using the decorator in Django?
easy
Solution
Step 1: Recall the correct decorator
Django uses@receiverto connect signal handlers, not@signal,@connect, or@listen.Step 2: Check function parameters
The handler must acceptsender,instance, and optionally**kwargs. @receiver(post_save, sender=MyModel) def my_handler(sender, instance, **kwargs): pass matches this.Final Answer:
@receiver(post_save, sender=MyModel) def my_handler(sender, instance, **kwargs): pass -> Option AQuick Check:
Use @receiver with correct params [OK]
Hint: Use @receiver decorator with sender and signal [OK]
Common Mistakes:
- Using wrong decorator names
- Missing sender argument
- Incorrect handler parameters
3. Given this code snippet, what will be printed when a new
Book instance is created?
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Book)
def announce_book(sender, instance, created, **kwargs):
if created:
print(f"New book added: {instance.title}")
book = Book.objects.create(title='Django Basics')medium
Solution
Step 1: Understand the signal and handler
Thepost_savesignal triggers after saving a model. The handler checks ifcreatedis True, meaning a new record.Step 2: Analyze the code execution
Creating a newBookinstance setscreated=True, so the print statement runs with the title.Final Answer:
New book added: Django Basics -> Option BQuick Check:
post_save with created=True prints title [OK]
Hint: Check 'created' flag to print on new records only [OK]
Common Mistakes:
- Ignoring the 'created' flag
- Assuming no output on create
- Confusing signal arguments
4. Identify the error in this signal handler connection code:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save)
def handler(sender, instance, **kwargs):
print('Saved!')medium
Solution
Step 1: Check the @receiver decorator usage
The@receiverdecorator requires the signal and optionally the sender. Omitting sender means the handler listens to all senders, which is allowed but often unintended.Step 2: Identify the likely error
Since the question asks for an error, the missing sender argument is the problem if the handler is meant for a specific model.Final Answer:
Missing sender argument in @receiver decorator -> Option AQuick Check:
Specify sender to target model signals [OK]
Hint: Always specify sender to avoid catching all signals [OK]
Common Mistakes:
- Not specifying sender when needed
- Assuming 'created' param is always required
- Misunderstanding **kwargs usage
5. You want to run a function only when a new
UserProfile is created, not when updated. Which is the best way to connect the signal handler?hard
Solution
Step 1: Identify the correct signal for creation
post_saveruns after saving, and thecreatedflag tells if it's a new record.Step 2: Choose the best method
Using@receiver(post_save, sender=UserProfile)and checkingcreatedinside the handler ensures the function runs only on creation.Final Answer:
Use @receiver(post_save, sender=UserProfile) and check if created is True inside the handler -> Option CQuick Check:
post_save + created=True = run on new only [OK]
Hint: Check 'created' flag in post_save for new records only [OK]
Common Mistakes:
- Using pre_save which runs before saving
- Using post_delete which runs on deletion
- Ignoring the created flag and running always
