Bird
Raised Fist0
Djangoframework~10 mins

pre_save and post_save signals in Django - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - pre_save and post_save signals
Model instance about to save
pre_save signal triggered
Instance saved to DB
post_save signal triggered
Further actions or cleanup
When saving a model, Django first triggers pre_save signal before saving, then saves the instance, and finally triggers post_save signal after saving.
Execution Sample
Django
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver

@receiver(pre_save, sender=MyModel)
def before_save(sender, instance, **kwargs):
    print('Before saving:', instance)

@receiver(post_save, sender=MyModel)
def after_save(sender, instance, created, **kwargs):
    print('After saving:', instance, 'Created:', created)
This code listens for pre_save and post_save signals on MyModel and prints messages before and after saving.
Execution Table
StepSignal/EventInstance StateActionOutput
1Call save() on instanceInstance with dataTrigger pre_save signalPrint 'Before saving: <instance>'
2pre_save signalInstance with dataRun before_save handlerPrint message before DB save
3Save instance to DBInstance savedDatabase write operationNo output
4Trigger post_save signalInstance savedRun after_save handlerPrint 'After saving: <instance> Created: True/False'
5End of save()Instance savedReturn from save()No output
💡 Save process completes after post_save signal handler runs
Variable Tracker
VariableStartAfter Step 1After Step 3After Step 4Final
instanceNew unsaved objectReady to saveSaved in DBSaved in DBSaved in DB
createdN/AN/AN/ATrue if new, False if updateTrue/False
Key Moments - 3 Insights
Why does pre_save run before the instance is saved to the database?
Because pre_save signal is designed to let you modify or check the instance before it is saved, as shown in execution_table step 2.
What does the 'created' parameter in post_save indicate?
'created' is True if the instance was newly created and saved, False if it was an update, as shown in execution_table step 4.
Can changes made in pre_save affect what is saved to the database?
Yes, because pre_save runs before saving, any changes to the instance in pre_save will be saved, as implied in the flow and execution_table.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step is the instance actually saved to the database?
AStep 3
BStep 2
CStep 4
DStep 1
💡 Hint
Check the 'Action' column for the database write operation in execution_table row 3.
According to variable_tracker, what is the value of 'created' after step 4?
AAlways True
BAlways False
CTrue if new instance, False if update
DUndefined
💡 Hint
Look at the 'created' row in variable_tracker after step 4.
If you modify the instance in pre_save, when will those changes be saved?
AImmediately after pre_save signal finishes
BDuring the save operation in step 3
CAfter post_save signal
DThey won't be saved
💡 Hint
Refer to concept_flow and execution_table steps 2 and 3 about when saving happens.
Concept Snapshot
Django signals pre_save and post_save run around model saving.
pre_save runs before saving, allowing changes before DB write.
post_save runs after saving, useful for actions after save.
Use @receiver decorator to connect handlers.
'created' in post_save shows if instance is new or updated.
Full Transcript
When you save a Django model instance, the pre_save signal runs first. This lets you check or change the instance before it goes into the database. Then Django saves the instance to the database. After saving, the post_save signal runs. It tells you the save is done and whether the instance was new or updated. You connect functions to these signals using the @receiver decorator. This way, you can run code automatically before or after saving a model.

Practice

(1/5)
1. What is the main purpose of the pre_save signal in Django?
easy
A. To run code after a model instance is deleted
B. To run code before a model instance is saved to the database
C. To run code after a model instance is saved to the database
D. To validate form data before submission

Solution

  1. Step 1: Understand the timing of pre_save

    The pre_save signal triggers just before saving a model instance to the database.
  2. Step 2: Compare with other signals

    post_save runs after saving, and deletion signals run on delete, so they don't match pre_save.
  3. Final Answer:

    To run code before a model instance is saved to the database -> Option B
  4. Quick 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
A. post_save.connect(my_handler, sender=Book)
B. post_save.connect(Book, sender=my_handler)
C. Book.post_save.connect(my_handler)
D. connect.post_save(my_handler, Book)

Solution

  1. Step 1: Recall the signal connection syntax

    The correct syntax is signal.connect(handler_function, sender=ModelClass).
  2. Step 2: Match the syntax to options

    post_save.connect(my_handler, sender=Book) matches this pattern exactly, connecting my_handler to post_save for Book.
  3. Final Answer:

    post_save.connect(my_handler, sender=Book) -> Option A
  4. Quick 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 save
medium
A. Updated: Alice
B. Created: Alice Before saving: Alice
C. Before saving: Alice Created: Alice
D. Before saving: Alice Updated: Alice

Solution

  1. Step 1: Understand signal order on save

    pre_save runs before saving, so it prints 'Before saving: Alice' first.
  2. Step 2: Check post_save behavior for new instance

    post_save runs after saving; since created=True, it prints 'Created: Alice'.
  3. Final Answer:

    Before saving: Alice Created: Alice -> Option C
  4. Quick 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
A. Missing sender argument in @receiver decorator
B. Signal handler must be named post_save_handler
C. post_save signal cannot be used with Product model
D. print statement should be inside a try-except block

Solution

  1. Step 1: Check the @receiver decorator usage

    The @receiver(post_save) decorator needs a sender=ModelClass argument to connect specifically to Product.
  2. Step 2: Understand why handler runs for all

    Without sender=Product, the handler listens to post_save for all models, causing it to run whenever any model is saved.
  3. Final Answer:

    Missing sender argument in @receiver decorator -> Option A
  4. Quick 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
A. Use a form validation method to set slug before saving
B. Use post_save signal to update slug after saving the instance
C. Override the model's save() method and set slug after calling super().save()
D. Use pre_save signal to check if slug is empty and set it from title

Solution

  1. Step 1: Identify when to set slug

    The slug should be set before saving to ensure it is stored correctly in the database.
  2. Step 2: Choose the right signal

    pre_save runs before saving, allowing modification of fields like slug before the database write.
  3. Step 3: Why not post_save or save override

    post_save runs after saving, so changing slug then requires another save. Overriding save() is possible but pre_save keeps logic separate and clean.
  4. Final Answer:

    Use pre_save signal to check if slug is empty and set it from title -> Option D
  5. Quick 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