These signals let you run code automatically before or after saving data in the database. It helps keep your app organized and react to changes easily.
pre_save and post_save signals 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 pre_save, post_save from django.dispatch import receiver from your_app.models import YourModel @receiver(pre_save, sender=YourModel) def before_save(sender, instance, **kwargs): # code to run before saving pass @receiver(post_save, sender=YourModel) def after_save(sender, instance, created, **kwargs): # code to run after saving # 'created' is True if new record was created pass
Use @receiver decorator to connect your function to the signal.
The instance is the actual model object being saved.
Examples
Django
from django.db.models.signals import pre_save from django.dispatch import receiver from myapp.models import Book @receiver(pre_save, sender=Book) def set_default_title(sender, instance, **kwargs): if not instance.title: instance.title = 'Untitled Book'
Django
from django.db.models.signals import post_save from django.dispatch import receiver from myapp.models import Book @receiver(post_save, sender=Book) def notify_new_book(sender, instance, created, **kwargs): if created: print(f'New book added: {instance.title}')
Sample Program
This example shows an Article model. Before saving, it sets a default title if none is given. After saving, it prints if the article was created or updated.
Django
from django.db import models from django.db.models.signals import pre_save, post_save from django.dispatch import receiver class Article(models.Model): title = models.CharField(max_length=100, blank=True) content = models.TextField() @receiver(pre_save, sender=Article) def ensure_title(sender, instance, **kwargs): if not instance.title: instance.title = 'Default Title' @receiver(post_save, sender=Article) def announce_article(sender, instance, created, **kwargs): if created: print(f'Article created: {instance.title}') else: print(f'Article updated: {instance.title}')
Important Notes
Signals run automatically without changing your save() calls.
Be careful to avoid infinite loops if you save inside a signal handler.
Use signals to keep code clean and separate concerns.
Summary
pre_save runs before saving data to check or modify it.
post_save runs after saving to react to changes.
Use signals to automate tasks and keep your app organized.
Practice
1. What is the main purpose of the
pre_save signal in Django?easy
Solution
Step 1: Understand the timing of
Thepre_savepre_savesignal triggers just before saving a model instance to the database.Step 2: Compare with other signals
post_saveruns after saving, and deletion signals run on delete, so they don't matchpre_save.Final Answer:
To run code before a model instance is saved to the database -> Option BQuick Check:
pre_save= before save [OK]
Hint: Remember: pre_save runs before saving data [OK]
Common Mistakes:
- Confusing pre_save with post_save
- Thinking pre_save runs after saving
- Mixing signals with form validation
2. Which of the following is the correct way to connect a
post_save signal to a model named Book?easy
Solution
Step 1: Recall the signal connection syntax
The correct syntax issignal.connect(handler_function, sender=ModelClass).Step 2: Match the syntax to options
post_save.connect(my_handler, sender=Book) matches this pattern exactly, connectingmy_handlertopost_saveforBook.Final Answer:
post_save.connect(my_handler, sender=Book) -> Option AQuick Check:
Signal.connect(handler, sender=Model) = correct [OK]
Hint: Signal.connect(handler, sender=Model) is the pattern [OK]
Common Mistakes:
- Swapping handler and sender arguments
- Trying to call connect on the model
- Using incorrect order of parameters
3. Given this code snippet, what will be printed when a new
Author instance is saved?from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
@receiver(pre_save, sender=Author)
def before_save(sender, instance, **kwargs):
print('Before saving:', instance.name)
@receiver(post_save, sender=Author)
def after_save(sender, instance, created, **kwargs):
if created:
print('Created:', instance.name)
else:
print('Updated:', instance.name)
# Assume instance.name = 'Alice' and this is a new savemedium
Solution
Step 1: Understand signal order on save
pre_saveruns before saving, so it prints 'Before saving: Alice' first.Step 2: Check post_save behavior for new instance
post_saveruns after saving; sincecreated=True, it prints 'Created: Alice'.Final Answer:
Before saving: Alice Created: Alice -> Option CQuick Check:
pre_save then post_save with created=True = Before saving: Alice Created: Alice [OK]
Hint: pre_save prints first, post_save with created=True prints second [OK]
Common Mistakes:
- Assuming post_save runs before pre_save
- Ignoring the created flag in post_save
- Mixing update and create messages
4. You wrote this signal handler but it runs whenever ANY model is saved (not specifically for
Product). What is the likely problem?from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save)
def product_saved(sender, instance, **kwargs):
print('Product saved:', instance.name)medium
Solution
Step 1: Check the @receiver decorator usage
The@receiver(post_save)decorator needs asender=ModelClassargument to connect specifically toProduct.Step 2: Understand why handler runs for all
Withoutsender=Product, the handler listens topost_savefor all models, causing it to run whenever any model is saved.Final Answer:
Missing sender argument in @receiver decorator -> Option AQuick Check:
@receiver(post_save, sender=Model) required [OK]
Hint: Always specify sender=Model in @receiver for signals [OK]
Common Mistakes:
- Omitting sender argument in @receiver
- Assuming handler name matters
- Thinking post_save can't be used with certain models
5. You want to automatically set a model's
slug field based on its title before saving, but only if the slug is empty. Which signal and approach is best?hard
Solution
Step 1: Identify when to set slug
The slug should be set before saving to ensure it is stored correctly in the database.Step 2: Choose the right signal
pre_saveruns before saving, allowing modification of fields likeslugbefore the database write.Step 3: Why not post_save or save override
post_saveruns after saving, so changing slug then requires another save. Overridingsave()is possible butpre_savekeeps logic separate and clean.Final Answer:
Use pre_save signal to check if slug is empty and set it from title -> Option DQuick Check:
Set fields before save with pre_save [OK]
Hint: Modify fields before saving with pre_save signal [OK]
Common Mistakes:
- Setting slug after saving causing extra saves
- Overriding save() but setting slug too late
- Using form validation which may not cover all saves
