Django on_delete Explained.

You may have used the Django on_delete argument in almost every Django project you’ve built. Most of us certainly have, but most of us probably have no idea what this ‘django on_delete’ argument does. This is because whenever we use a Foreignkey in our Django models, it is also mandatory that we add the on_delete argument.

You may have encountered an error like this before: -typeerror: __init__() missing 1 required positional argument: 'on_delete', which tells you there is a required argument that is missing, and that argument, is on_delete.  So, if this is you, who has only used the Django models on_delete argument just because it is required, but without actually knowing what it does, this post is for you.

So, let’s get started.

Table of Contents

What is Django on_delete?

On_delete, as the name suggests, is a required positional argument that tells Django what to do to objects that are referencing another object when that object being referenced gets deleted. This works for all database relationships which are Foreignkey (Django’s many-to-one relationship), Many-to-many relationship, and One-to-one relationship.

Example

Let’s take a look at the real-life usage of the on_delete argument:

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

class Movie(models.Model):
    title = models.CharField(max_length=100)
    description = models.CharField(max_length=250)
    image = models.ImageField(upload_to='movie/images/')
    url = models.URLField(blank=True)

    def __str__(self):
        return self.title


class Review(models.Model):
    text = models.CharField(max_length=200)
    date = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE) # here
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE) #here
    watchAgaim = models.BooleanField()

    def __str__(self):
        return self.text

In this example, we have two places where the on_delete argument is being used. In both cases, we are using the models.CASCADE option which is perhaps the most popular option for the on_delete argument. But before we move forward, let’s take some time to understand the syntax of the on_delete argument.

The Django on_delete syntax

In this subsection, pay attention to the vocabulary I will use.

movie = models.ForeignKey(Movie, on_delete=models.CASCADE)

movie (before the assignment operator) is the field that is being used to reference the parent object. It is a common practice to name it the same as the object it is referring to, especially in Many-to-one relationships. The movie field is one of the fields that belong to the Review table, and when these fields are being populated to create a new instance, movie will reference one of the Movie table instances.

Movie (first argument in brackets) is the referenced object, in other words, the object that is being referred to.

And on_delete is the second argument that requires one of the seven options that we will look at soon.

Django on_delete: Explanation

Both of these happen in the Review model.

Our Review model has five fields which are text, date, user, movie, and watchAgain. When the user input for the Review model is entered, all of the fields are entered manually except for the user and movie because they source records from other models called User and Movie respectively.

You do not see the User model here because it is provided by Django.

When a User instance gets deleted, all of the reviews that belong to this user are also deleted because of the CASCADE keyword, and when a Movie instance gets deleted, all the reviews that belong to that movie will be deleted as well.

I populated the database for this Django project and I dropped the db.sqlite3 file into an SQLite Viewer by Juraj Novรกk.

This first table is the User table.

django on_delete user table
User table

The next is the Movie table.

django on_delete Movie table
Movie table

And last but not least, the Review table:

django on_delete Review table

Take a look at the column on the right-most side. Each cell is referencing the user_id to which the corresponding review belongs. Looking back at the first table again, you can see that the author of the first review is cajo (user with id of 1), the author of the next three reviews is steve (user with id of 2), and the author of the last two reviews is wayne. Keeping in mind that we have set on_delete to CASCADE [on_delete=models.CASCADE], it means that when we delete a user, the reviews that belong to that user will get deleted as well. For example, if we delete wayne, the reviews with the id 5 and 6 will get deleted as well. The same applies to cajo and steve. Pardon the names.

Let’s take a look at the Movie and Review relationship. Take a look at the column on the second from the right position. With what we have learned from above, you can conclude that if we delete the Till movie, the reviews with the id 3 and 6 will get deleted, and so on and so forth.

This, however, does not happen the other way around. We know that if we delete a User, then the user’s reviews will get deleted; but if we delete a review, the user of that review will not be affected in any way. If we delete a movie, its reviews will be deleted, but if we delete a review that belongs to a movie, then the movie as well will not be affected.

I really hope you understood this section, fill free to hit me in the comments section if you didn’t or if you feel there is something I should explain more about the Django on_delete option.

Note: the instances are getting deleted because of the CASCADE option. In the next section, we will look at other options that Django provides us on top of the CASCADE option.

Django on_delete options

Apart from the CASCADE option that we have looked at in the previous django on_delete example, Django also offers quite a few other options that can be executed when a delete happens. In total, Django offers 7 on_delete options which are:

  1. CASCADE
  2. RESTRICT
  3. PROTECT
  4. SET_DEFAULT
  5. SET_NULL
  6. SET()
  7. DO_NOTHING

We will take a look at each one of these on_delete options in detail.

On_delete Option 1: CASCADE

In the Django models on_delete options, you can think of CASCADE as a synonym of the word delete. When CASCADE is in use, the instance that references gets deleted if the referenced object is deleted. models.CASCADE is the most commonly used on_delete option because it creates the least impact on data integrity. Just take a look at the example we have given above, when a movie gets deleted, its reviews will also get deleted, then in our database, there won’t be reviews that do not belong to any movie.

On_delete Option 3: PROTECT

movie = models.ForeignKey(Movie, on_delete=models.PROTECT)

The PROTECT option prevents the deletion of an instance that has references pointing to it. Using our movie app example, If we try to delete a movie that has reviews, we will get a ProtectedError. In order to delete that same movie instance, we are required to delete every review that belongs to that movie, then we can be able to delete the movie object. If the movie object still has other references apart from the reviews, then unless we also delete those, we will still get the ProtectedError.

On_delete Option 2: RESTRICT

movie = models.ForeignKey(Movie, on_delete=models.RESTRICT)

Restrict is quite more tricky than PROTECT but they function on the same basis. Just like Protect, Resctrict prevents the deletion of an instance that has refences pointing to it but only lets the deletion happen when the object that is referencing is also part of another different CASCADE relationship.

On_delete Option 4: SET_DEFAULT

Using SET_DEFAULT as a django on_delete option will set the value of the field to the default one provided. As you may have figured out, the default value should be available or else, it won’t work.

movie = models.ForeignKey(Movie, default = 'Not available', on_delete=models.SET_DEFAULT)

On_delete Option 5: SET_NULL

Using SET_DEFAULT as a django on_delete option will set the value of the field to NULL. Just like set_default, Null should also be set to true for that field. Check out my post on django null vs blank to learn more about the NULL value.

movie = models.ForeignKey(Movie, null = True, on_delete=models.SET_NULL)

On_delete Option 6: SET()

Using SET_DEFAULT as a django on_delete option will set the value of the field to the one that is passed into the set() function.

On_delete Option 7: DO_NOTHING

Well, it does nothing! As simple as that.

Conclusion:

We have finally hit the conclusion and all I want to say here is be thoughtful of the on_delete options that you are going to use before you use them. It is so easy to use one option in a situation that does not suit it very well. For most of your projects, you are mostly going to be using the models.CASCADE option, but when you start venturing into these other on_delete options you have to be careful to use them appropriately. That was all.

If you did not understand what we where talking about here, let’s get in touch in the comments section below. I will be happy to help. Peace!

Stephen Mclin
Stephen Mclin

Hey, I'm Steve; I write about Python and Django as if I'm teaching myself. CodingGear is sort of like my learning notes, but for all of us. Hope you'll love the content!

Articles: 90