Signals let parts of your Django app talk to each other automatically when something happens. They help keep your code organized and avoid repeating yourself.
When signals are appropriate vs not 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: # do something when a new instance is created pass
Use @receiver decorator to connect a function to a signal.
The handler function receives the sender model, the instance, and extra info.
Examples
Django
from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=User) def send_welcome_email(sender, instance, created, **kwargs): if created: print(f"Send welcome email to {instance.email}")
Django
from django.db.models.signals import pre_delete from django.dispatch import receiver @receiver(pre_delete, sender=Article) def log_article_deletion(sender, instance, **kwargs): print(f"Article {instance.title} is about to be deleted")
Sample Program
This example shows a signal that warns when product stock is low after saving.
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 {instance.name}") # Simulate saving products p1 = Product(name='Pen', stock=10) p1.save() # No warning p2 = Product(name='Notebook', stock=3) p2.save() # Warning printed
Important Notes
Signals can make debugging harder if overused because the flow is less obvious.
Don't use signals for complex business logic; keep them for simple side effects.
For very simple cases, calling functions directly might be clearer than signals.
Summary
Use signals to react automatically to model events without changing model code.
Signals are great for small side tasks like notifications or logging.
Avoid signals when the logic is complex or when direct calls are simpler and clearer.
Practice
1. Which situation is best suited for using Django signals?
easy
Solution
Step 1: Understand signal purpose
Django signals are designed to react automatically to events like model saves without changing the model code.Step 2: Match use case to signals
Sending an email notification after user registration is a small side task that fits well with signals.Final Answer:
Sending an email notification after a user registers -> Option AQuick Check:
Signals = small side tasks [OK]
Hint: Use signals for small automatic reactions, not complex logic [OK]
Common Mistakes:
- Using signals for complex validation
- Overriding model methods instead of signals
- Calling functions directly when signals fit better
2. Which of the following is the correct way to connect a Django signal?
easy
Solution
Step 1: Recall Django signal syntax
The correct syntax to connect a signal is using the signal's connect method with the handler and sender model.Step 2: Identify correct syntax
post_save.connect(my_handler, sender=MyModel) matches Django's documented pattern.Final Answer:
post_save.connect(my_handler, sender=MyModel) -> Option AQuick Check:
Signal connect syntax = post_save.connect(my_handler, sender=MyModel) [OK]
Hint: Remember: signal.connect(handler, sender=Model) [OK]
Common Mistakes:
- Swapping argument order
- Calling signal as a method on model
- Using undefined connect_signal function
3. Given this code snippet, what will happen when a new
Book instance is saved?from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Book)
def notify_author(sender, instance, created, **kwargs):
if created:
print(f"Notify {instance.author} about new book")
book = Book(title='Django Tips', author='Alice')
book.save()medium
Solution
Step 1: Understand signal decorator usage
The @receiver decorator connects the notify_author function to post_save for Book automatically.Step 2: Check signal behavior on save
When a new Book instance is saved, created=True, so the print statement runs with author 'Alice'.Final Answer:
Prints 'Notify Alice about new book' -> Option BQuick Check:
post_save with created=True triggers print [OK]
Hint: @receiver auto-connects signals; created=True means new instance [OK]
Common Mistakes:
- Assuming signals need manual connect with @receiver
- Thinking created is False on new save
- Ignoring the print inside the signal handler
4. What is wrong with this signal usage?
from django.db.models.signals import post_save
post_save.connect(handle_save)
def handle_save(sender, instance, **kwargs):
print('Saved!')medium
Solution
Step 1: Check order of function definition and connection
The handler function handle_save is connected before it is defined, causing a NameError.Step 2: Understand Python execution order
Python reads top to bottom, so handle_save must be defined before connecting it.Final Answer:
The signal handler is connected before it is defined -> Option DQuick Check:
Define handler before connecting signal [OK]
Hint: Define handler before connecting signals [OK]
Common Mistakes:
- Ignoring function order
- Assuming sender is always required
- Thinking signal handlers must return values
5. You want to update a user's profile data immediately after the user is created, but the update requires complex logic involving multiple models and external API calls. What is the best approach?
hard
Solution
Step 1: Evaluate complexity and clarity
Complex logic with multiple models and external calls is better handled explicitly for clarity and error handling.Step 2: Choose direct call over signals for complex tasks
Calling a dedicated function directly after user creation in the view keeps logic clear and easier to debug.Final Answer:
Call a dedicated function directly after user creation in the view -> Option CQuick Check:
Complex logic = direct calls, not signals [OK]
Hint: Use direct calls for complex logic, signals for simple tasks [OK]
Common Mistakes:
- Putting complex logic inside signals
- Overriding save for unrelated tasks
- Relying on signals for all side effects
