When working with Django, you may need to run custom logic immediately before a model instance is saved to the database. I’ve found Django’s pre_save signal to be a useful tool for this. It allows you to hook into the save process and perform actions such as data validation, auto-populating fields, or even preventing a save under specific conditions.
In this article, I’ll walk you through what the pre_save signal is, why it’s useful, and how to use it effectively with clear, practical examples.
Let’s get in!
What is the Django pre_save Signal?
Django signals are a way to allow decoupled applications to get notified when certain actions occur elsewhere in the framework. The pre_save signal is sent just before a model’s save() method is called, but before the data is written to the database.
This means you can intercept the save process, modify the instance, or even raise errors before the record is saved.
Check out Create a Function-Based View in Django
How to Use Django pre_save Signal
Let me show you the steps to use the Django pre_save signal.
Step 1: Import Necessary Modules
First, you need to import Django’s signal system and your model:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import OrderStep 2: Define a Signal Receiver Function
This function will run every time before an Order instance is saved.
@receiver(pre_save, sender=Order)
def before_order_save(sender, instance, **kwargs):
# Example: Automatically set order status to 'Pending' if not set
if not instance.status:
instance.status = 'Pending'
# Example: Validate that the order quantity is positive
if instance.quantity <= 0:
raise ValueError("Order quantity must be greater than zero.")Step 3: Connect the Signal (Optional if using @receiver)
Using the @receiver decorator automatically connects the signal. Alternatively, you can connect manually:
pre_save.connect(before_order_save, sender=Order)Read Create a Web Form in Python Django
Full Example: Use pre_save in a Real-World US E-commerce Scenario
Imagine you’re building an e-commerce platform serving customers in the US. You want to ensure that, before an order is saved:
- The order’s
statusfield defaults to"Pending"if not set. - The
shipping_stateis always stored in uppercase (e.g., “CA” for California). - The
order_totalis recalculated based on the quantity and unit price.
Here’s how you can do it with pre_save:
# models.py
from django.db import models
class Order(models.Model):
customer_name = models.CharField(max_length=100)
shipping_state = models.CharField(max_length=2) # US state abbreviation
quantity = models.PositiveIntegerField()
unit_price = models.DecimalField(max_digits=8, decimal_places=2)
order_total = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
status = models.CharField(max_length=20, blank=True, null=True)
def __str__(self):
return f"Order #{self.id} for {self.customer_name}"# signals.py
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import Order
@receiver(pre_save, sender=Order)
def before_order_save(sender, instance, **kwargs):
# Default status to 'Pending' if empty
if not instance.status:
instance.status = 'Pending'
# Ensure shipping_state is uppercase (e.g., CA, NY)
if instance.shipping_state:
instance.shipping_state = instance.shipping_state.upper()
# Validate quantity
if instance.quantity <= 0:
raise ValueError("Order quantity must be greater than zero.")
# Calculate order total
instance.order_total = instance.quantity * instance.unit_priceStep 4: Register the Signal
Make sure your signal handlers are imported when Django starts. The best practice is to import your signals inside your app’s apps.py:
# apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
import myapp.signalsThen update your app’s __init__.py to use this config:
default_app_config = 'myapp.apps.MyAppConfig'

Check out Build a Contact Form in Django using Bootstrap
Alternative: Overriding the save() Method vs Using pre_save
I’ve often been asked whether to use pre_save or override the model’s save() method. Here’s my take:
- Use pre_save if you want to keep model logic clean and allow multiple listeners.
- Override
save()if the logic is tightly coupled with the model, and you want everything in one place.
Both approaches work, but signals provide better separation of concerns.
Read Create a Form with Django Crispy Forms
Things to Keep in Mind
- pre_save runs every time you save a model instance, including updates.
- Avoid heavy processing inside signals to prevent slowing down saves.
- Be careful with exceptions inside signals; raising errors will prevent saving.
- Always test your signals thoroughly.
Using Django’s pre_save signal has saved me countless hours by automating repetitive tasks and enforcing rules consistently. Once you get the hang of it, you’ll find signals to be a powerful addition to your Django toolkit.
Other Django articles you may also like:
- Build a Django Contact Form with Email
- Add Google reCAPTCHA to Django Form
- Create a Contact Form with Django and SQLite

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.