Table of contents
1.
Introduction
2.
How to override the save method?
2.1.
Take action before a database operation
2.2.
Take action after a database operation     
2.3.
Making use of signals
2.4.
Using the signal pre_save
2.5.
Using the signal post_save
3.
Frequently Asked Questions
4.
Key takeaway
Last Updated: Mar 27, 2024

How to override the save method in Django Models

Author Aditya Kumar
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

The save method is model-inherited. This model is used to keep an instance into a specific Model. The save() function is used whenever the admin interface or the Django shell generates a model instance. Before storing the data in the database, we can change the save function to apply some constraints or fill some ready-to-use fields like SlugField.

Technically, overriding the save method to create such functionality is not encouraged because any problem in the same technique can cause the entire database to crash. So, if you're good at developing save methods and error handling, don't bother with save methods and instead strive to integrate these features in forms, views, models, and so on.

How to override the save method?

Here are the following ways to achieve this:

Take action before a database operation

Assume you have a database of blogs, and each blog requires a slug, which must be kept read-only and generated automatically when a blog is created.

You can achieve this by override the save method and setting the value of this field before running the determine to save mode:

from django.db import models
from django.utils.text import slugify 

# Create your models here.
class Blog(models.Model):
    title = models.CharField(max_length = 50)
    description = models.CharField(max_length = 200)
    slug = models.SlugField()


    def save(self, *args, **kwargs):
        # Using the regular field, set the value of the read-only field.
        self.slug = slugify(self.title)

        # call the parent's save() method
        super(Blog, self).save(*args, **kwargs)
You can also try this code with Online Python Compiler
Run Code

Take action after a database operation     

Consider the situation when you're developing appointment scheduling software. Every time your users create a new appointment, you should send them an email with the information about that appointment.

For improved resiliency, this operation should be done after the appointment has been saved in the database, and it may do it by sending your email after the super method called:

from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Appointment(models.Model):
    title = models.CharField(max_length=100)
    description = models.CharField(max_length=255)
    appointment_time = models.DateTimeField()
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        super(Appointment, self).save(*args, **kwargs)

        # send the user an email to schedule an appointment
        send_email(self.user.email, self.title, self.description, self.appointment_time)
You can also try this code with Online Python Compiler
Run Code

Making use of signals

Override the save method can be helpful, but there is a drawback.

If you need to do numerous business logics that aren't related at the same time when saving an object, you'll have to do it all inside the save method.

This will clog up the save method and make the code unreadable. It will be more challenging to isolate the malfunctioning function when fixing bugs.

Instead, Django signals are a better option. Django provides several built-in signals that alert a specific method of an action allowing the process to perform business logic.

The pre_save and post_save signals can provide the above capability of doing operations before or after saving an entry in the database.

Using the signal pre_save

A pre_save signal can be used to achieve the above example of creating a slug before storing a blog article into the database:

from django.db import models
from django.utils.text import slugify 

from django.db.models.signals import pre_save
from django.dispatch import receiver


# Create your models here.
class Blog(models.Model):
    title = models.CharField(max_length = 50)
    description = models.CharField(max_length = 200)
    slug = models.SlugField()


@receiver(pre_save, sender=Blog)
def create_slug(sender, instance, *args, **kwargs):
    instance.slug = slugify(instance.title)

@receiver(pre_save, sender=Blog)
def other_pre_save_actions(sender, instance, *args, **kwargs):
    # here, do a new type of pre_save action
    pass
You can also try this code with Online Python Compiler
Run Code


We didn't have to override the save function at all, as you can see, which decouples the logic of producing a slug. The pre_save signal can be received by any number of receivers, each of which can do distinct actions.

This signal is called before the save method is called, and the object will not be saved if any of these signals throws an exception.

Using the signal post_save

This is similar to the pre_save signal, except it is called after the save procedure.

An example shows us how to utilise it, using the prior model way of sending an email on appointment confirmation.

from django.db import models
from django.contrib.auth.models import User

from django.db.models.signals import post_save
from django.dispatch import receiver

# Create your models here.
class Appointment(models.Model):
    title = models.CharField(max_length=100)
    description = models.CharField(max_length=255)
    appointment_time = models.DateTimeField()
    user = models.ForeignKey(User, on_delete=models.CASCADE)

@receiver(post_save, sender=Appointment)
def send_appointment_confirmation_email(sender, instance, created, **kwargs):
  if created:
    send_email(instance.user.email, instance.title, instance.description, instance.appointment_time)

@receiver(post_save, sender=Appointment)
def other_post_save_actions(sender, instance, created, **kwargs):
   # here, do a separate type of post_save action
   pass
You can also try this code with Online Python Compiler
Run Code

 

This signal also indicates whether the object is being developed for the first time or not. We will only send the appointment confirmation email once the appointment is made for the first time.

We must verify that the email is not sent several times because this signal is called every time the object is saved.

Frequently Asked Questions

  1. What is the save() method?
    The save() method is called whenever a new model instance is created, whether through the admin interface or the shell. Before storing the data in the database, you can override the save() function to add new or remove existing data.
     
  2. Difference between pre_save and post_save signal.
    pre_save is used before the model is saved, while post save is used after the model. This is where you handle data before saving, for example, to ensure that the data is legitimate or post_save after the model has been committed to attaching a file.

Key takeaway

Finally, using pre_save and post_save signals rather than overriding a save method is more elegant. In general, whether you opt to override the save mechanism or employ signals, you must exercise caution while conducting these types of tasks.For example, in the previous instances of a Blog model, the slug is preserved each time the blog entry is updated. To summarise, do not override the save function or use signals until you are confident that all of these edge circumstances have been addressed.

You may also want to explore more articles on Django then you can visit our archives on Django where you can find more relevant topics related to Django such as top interview questions in Django or beginning with Django.

Live masterclass