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)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)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
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
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.




