Bird
Raised Fist0
Djangoframework~10 mins

pre_delete and post_delete 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_delete and post_delete signals
Delete request triggered
pre_delete signal sent
Object deletion from DB
post_delete signal sent
Cleanup or follow-up actions
When deleting an object, Django first sends a pre_delete signal, then deletes the object, and finally sends a post_delete signal for any cleanup.
Execution Sample
Django
from django.db.models.signals import pre_delete, post_delete
from django.dispatch import receiver

@receiver(pre_delete, sender=MyModel)
def before_delete(sender, instance, **kwargs):
    print(f"About to delete: {instance}")

@receiver(post_delete, sender=MyModel)
def after_delete(sender, instance, **kwargs):
    print(f"Deleted: {instance}")
This code prints messages before and after deleting a MyModel instance.
Execution Table
StepSignal/EventActionInstance StateOutput
1Delete requestUser calls delete()Instance exists in DBNo output
2pre_deleteSignal sent before deletionInstance still existsPrints: About to delete: <instance>
3Delete objectObject removed from DBInstance removedNo output
4post_deleteSignal sent after deletionInstance no longer in DBPrints: Deleted: <instance>
5EndNo more actionsInstance deletedProcess complete
💡 Deletion process ends after post_delete signal is sent
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4Final
instanceExists in DBExists in DBDeleted from DBDeleted from DBDeleted from DB
Key Moments - 3 Insights
Why does pre_delete signal see the instance still in the database?
Because pre_delete is sent before the actual deletion (see execution_table step 2), the instance still exists in the database at that moment.
Can post_delete signal access the instance data?
Yes, post_delete receives the instance data but the object is already deleted from the database (execution_table step 4). The instance is a copy passed to the signal.
What happens if deletion is canceled during pre_delete?
If an error or exception occurs in pre_delete handlers, the deletion can be stopped before step 3, so post_delete won't run.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the state of the instance at step 3?
AInstance still exists in the database
BInstance has been deleted from the database
CInstance is being deleted but still accessible
DInstance is recreated
💡 Hint
Check the 'Instance State' column at step 3 in the execution_table
At which step does the pre_delete signal run?
AStep 2
BStep 1
CStep 3
DStep 4
💡 Hint
Look at the 'Signal/Event' column in the execution_table
If the pre_delete signal raises an error, what happens next?
Apost_delete runs but deletion is rolled back
BDeletion continues and post_delete runs
CDeletion stops and post_delete does not run
DNothing happens, deletion proceeds normally
💡 Hint
Refer to key_moments about cancellation during pre_delete
Concept Snapshot
Django deletion flow:
- pre_delete signal fires before object is deleted
- Object is deleted from database
- post_delete signal fires after deletion
Use pre_delete to prepare or cancel deletion
Use post_delete for cleanup after deletion
Full Transcript
When you delete an object in Django, the system first sends a pre_delete signal. This happens before the object is removed from the database, so the instance still exists and can be accessed. After that, Django deletes the object from the database. Then, it sends a post_delete signal, which happens after the object is gone. The post_delete signal still receives the instance data but the object no longer exists in the database. If an error happens during pre_delete, the deletion can stop and post_delete will not run. This lets you prepare or cancel deletions and clean up after deletions safely.

Practice

(1/5)
1. What is the main difference between Django's pre_delete and post_delete signals?
easy
A. pre_delete runs after a record is deleted, post_delete runs before.
B. pre_delete runs before a record is deleted, post_delete runs after.
C. Both signals run at the same time during deletion.
D. pre_delete only works with models, post_delete only with forms.

Solution

  1. Step 1: Understand signal timing

    pre_delete is triggered just before a model instance is deleted from the database.
  2. Step 2: Understand post_delete timing

    post_delete is triggered immediately after the instance has been deleted.
  3. Final Answer:

    pre_delete runs before a record is deleted, post_delete runs after. -> Option B
  4. Quick Check:

    Signal timing difference = pre_delete runs before a record is deleted, post_delete runs after. [OK]
Hint: Remember: pre_delete before removal, post_delete after removal [OK]
Common Mistakes:
  • Confusing the order of signal execution
  • Thinking both signals run simultaneously
  • Assuming signals work only with forms
2. Which of the following is the correct way to connect a pre_delete signal to a model named Book?
easy
A. Book.pre_delete.connect(my_handler)
B. post_delete.connect(my_handler, sender=Book)
C. pre_delete.connect(my_handler, sender=Book)
D. connect(pre_delete, my_handler, Book)

Solution

  1. Step 1: Recall signal connection syntax

    In Django, signals are connected using signal.connect(handler, sender=Model).
  2. Step 2: Apply to pre_delete and Book

    Use pre_delete.connect(my_handler, sender=Book) to connect the handler to the Book model.
  3. Final Answer:

    pre_delete.connect(my_handler, sender=Book) -> Option C
  4. Quick Check:

    Correct connect syntax = pre_delete.connect(my_handler, sender=Book) [OK]
Hint: Use signal.connect(handler, sender=Model) to connect signals [OK]
Common Mistakes:
  • Using post_delete instead of pre_delete
  • Trying to call connect on the model itself
  • Incorrect argument order in connect
3. Given this code snippet, what will be printed when a Book instance is deleted?
from django.db.models.signals import pre_delete, post_delete
from django.dispatch import receiver

@receiver(pre_delete, sender=Book)
def before_delete(sender, instance, **kwargs):
    print(f"Deleting book: {instance.title} (pre_delete)")

@receiver(post_delete, sender=Book)
def after_delete(sender, instance, **kwargs):
    print(f"Deleted book: {instance.title} (post_delete)")

book = Book(title='Django Basics')
book.delete()
medium
A. Deleting book: Django Basics (pre_delete) Deleted book: Django Basics (post_delete)
B. Deleted book: Django Basics (post_delete) Deleting book: Django Basics (pre_delete)
C. Only Deleting book: Django Basics (pre_delete) is printed
D. No output is printed

Solution

  1. Step 1: Understand signal order on deletion

    pre_delete runs before the instance is deleted, so its print runs first.
  2. Step 2: Understand post_delete runs after deletion

    After deletion, post_delete signal triggers, printing the second message.
  3. Final Answer:

    Deleting book: Django Basics (pre_delete) Deleted book: Django Basics (post_delete) -> Option A
  4. Quick Check:

    Signal print order = Deleting book: Django Basics (pre_delete) Deleted book: Django Basics (post_delete) [OK]
Hint: pre_delete prints before delete, post_delete prints after [OK]
Common Mistakes:
  • Assuming post_delete prints before pre_delete
  • Expecting only one signal to run
  • Forgetting to call delete() on the instance
4. What is wrong with this code that tries to use pre_delete signal?
from django.db.models.signals import pre_delete

@pre_delete(sender=Author)
def cleanup(sender, instance, **kwargs):
    print('Cleaning up author data')
medium
A. Using @pre_delete decorator is incorrect; should use @receiver instead.
B. Missing import for Author model.
C. Signal handler must return a value.
D. The function name 'cleanup' is reserved and cannot be used.

Solution

  1. Step 1: Check signal handler decoration

    Django signals use the @receiver(signal, sender=Model) decorator, not @pre_delete(sender=Model).
  2. Step 2: Confirm correct decorator usage

    Replace @pre_delete(sender=Author) with @receiver(pre_delete, sender=Author) to fix the error.
  3. Final Answer:

    Using @pre_delete decorator is incorrect; should use @receiver instead. -> Option A
  4. Quick Check:

    Use @receiver for signals, not @pre_delete [OK]
Hint: Use @receiver(signal, sender=Model) to decorate signal handlers [OK]
Common Mistakes:
  • Using signal name as decorator directly
  • Forgetting to import @receiver
  • Assuming signal handlers must return values
5. You want to automatically delete all Comment objects related to a Post before the Post itself is deleted. Which signal and approach is best?
hard
A. Use post_delete on Comment to delete the post after comments are removed.
B. Use post_delete on Post to delete related Comment objects after the post is removed.
C. Use pre_delete on Comment to delete the post before comments are removed.
D. Use pre_delete on Post to delete related Comment objects before the post is removed.

Solution

  1. Step 1: Understand deletion order requirement

    Comments must be deleted before the post to avoid foreign key errors.
  2. Step 2: Choose correct signal and model

    pre_delete on Post allows deleting related comments before the post is removed.
  3. Final Answer:

    Use pre_delete on Post to delete related Comment objects before the post is removed. -> Option D
  4. Quick Check:

    Delete related objects in pre_delete to avoid FK errors [OK]
Hint: Delete related objects in pre_delete to prevent FK constraint errors [OK]
Common Mistakes:
  • Deleting related objects after post deletion causes errors
  • Using signals on wrong model
  • Trying to delete parent in comment signals