9

I read the django documentation about PROTECT and RESTRICT to use with "on_delete".

  • PROTECT

Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.

Example:

class MyModel(models.Model):
    field = models.ForeignKey(YourModel, on_delete=models.PROTECT)
  • RESTRICT

Prevent deletion of the referenced object by raising RestrictedError (a subclass of django.db.IntegrityError). Unlike PROTECT, deletion of the referenced object is allowed if it also references a different object that is being deleted in the same operation, but via a CASCADE relationship.

Example:

class MyModel(models.Model):
    field = models.ForeignKey(YourModel, on_delete=models.RESTRICT)

To some degree, I could understand the difference between PROTECT and RESTRICT but not exactly so what is the difference between PROTECT and RESTRICT exactly? and when should I use them?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129

4 Answers4

10

Based on Django documentation RESTRICT allows you to delete your referenced object in some special situations. For instance:

class Artist(models.Model):
    name = models.CharField(max_length=10)

class Album(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)

class Song(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    album = models.ForeignKey(Album, on_delete=models.RESTRICT)

As you can see, if you create an album instance and after that create a song instance with the same artist (now you have a song and also an album with the same artist), then you can simply delete that artist without any problem (since in this deleting operation you're also deleting related objects. Also note that artist has CASCADE on song and album deletion). But if you have defined PROTECT instead of RESTRICT, like:

class Song(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    album = models.ForeignKey(Album, on_delete=models.PROTECT)

you couldn't have deleted your artist instance because that artist is referenced by this song. If you ask me, I would say RESTRICT is another version of PROTECT with less limitation on object deletion. If this explanation is not clear so far I would recommend you Django example itself:

Artist can be deleted even if that implies deleting an Album which is referenced by a Song, because Song also references Artist itself through a cascading relationship. For example:

artist_one = Artist.objects.create(name='artist one')
artist_two = Artist.objects.create(name='artist two')
album_one = Album.objects.create(artist=artist_one)
album_two = Album.objects.create(artist=artist_two)
song_one = Song.objects.create(artist=artist_one, album=album_one)
song_two = Song.objects.create(artist=artist_one, album=album_two)
album_one.delete()

Raises RestrictedError.

artist_two.delete()

Raises RestrictedError.

artist_one.delete()  
(4, {'Song': 2, 'Album': 1, 'Artist': 1})

Will successfully delete your object

Using different types of on_delete is really related to your design and your constraints on deleting your objects. So, basically when you want to just protect your object from deletion (without any dependencies), using PROTECT is your best solution because with using RESTRICT in this case, you force Django to look in every related object (a nested for loop) for checking if other relations will be deleted in this process or not and it might have bad impact on your deletion performance.

Roham
  • 1,970
  • 2
  • 6
  • 16
  • You kinda just repeated the docs, which I had already read before coming here, and yet still didn't quite understand. – odigity Jun 18 '22 at 12:52
  • Everything is really clear and I think docs are more than enough... maybe you should ask someone who is expert to help you understand it... also there are some points in my answer that do not exist in the docs if you read it more carefully. Good luck! – Roham Jun 19 '22 at 15:29
  • Please provide proper attribution to copied content, you have indicated that you show an example from Django's documentation but you need to quote the parts you have copied verbatim (This includes not only code but text also). You also need to give a link to the source. – Abdul Aziz Barkat Jun 28 '22 at 12:38
6

Based on the real world applications requirement, we use both for different purpose.

PROTECT never deletes and raises error. But, RESTRICT (introduced from Django 3.1) deletes in some cases, not all.

PROTECT example: According to how to prevent deletion,

class Employee(models.Model):
    name = models.CharField(name, unique=True)

class Project(models.Model):
    name = models.CharField(name, unique=True)
    employees = models.ForeignKey(Employee, on_delete=models.PROTECT)

PROTECT explanation: Think from real worlds perspective. There will be many Employees and an Employee can have multiple Projects. If we delete an Employee if he has multiple Projects associated with it, the project objects in Project model will be remained. This is wrong. If Employee has done any Projects, he (Employee object) can't be deleted. Hence we used PROTECT. This would work to prevent the deletion of any Employee object that has one or more Project object(s) associated with it.

You need to understand CASCADE first before understanding RESTRICT:

CASCADE example:

class Artist(models.Model):
    name = models.CharField(max_length=10)

class Album(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)

CASCADE explanation: Think from real worlds perspective. There will be many Artists and an Artist can have multiple Albums. If we want to delete an Artist and his/her related Albums, we will use CASCADE. Remember, CASCADE deletes. It always deletes.

RESTRICT example:

class Artist(models.Model):
    name = models.CharField(max_length=10)

class Album(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)

class Song(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    album = models.ForeignKey(Album, on_delete=models.RESTRICT)

RESTRICT explanation: Now, think once again from the real world perspective. An Artist will have zero or more Albums. An Album can have zero or more Songs. There is no problem in deleting if an Artist have zero Albums and an Album have zero Songs. In fact, there is no relation since Artist doesn't have any Albums at all. The deletion problem arises and the scenario starts when an Artist has multiple Albums and an Album has multiple Songs. Here's how:

RESTRICT and PROTECT works the same way. But, PROTECT is of two steps. Parent and Child. If we shouldn't delete a Child (Album), we shouldn't delete a Parent (Artist). In other words, we use PROTECT if we don't want our Child (Album) deleted if Parent(Artist) deleted. PROTECT protects from deletion of objects.

And, RESTRICT is of three steps. Parent and Child and Grand Child. RESTRICT (a limiting condition or measure) only restricts from deletion of objects up to a certain limit.

You need to understand a real world scenario why we use RESTRICT. Lets say there are multiple Artists. Each Artists have multiple Albums. Each Album has multiple songs. see the below code

>>> artist_one = Artist.objects.create(name='artist one')
>>> artist_two = Artist.objects.create(name='artist two')
>>> album_one = Album.objects.create(artist=artist_one)
>>> album_two = Album.objects.create(artist=artist_two)
>>> song_one = Song.objects.create(artist=artist_one, album=album_one)
>>> song_two = Song.objects.create(artist=artist_one, album=album_two)
>>> album_one.delete()
# Raises RestrictedError.
>>> artist_two.delete()
# Raises RestrictedError.
>>> artist_one.delete()
(4, {'Song': 2, 'Album': 1, 'Artist': 1})

Note that, from above code,

  • song_one and song_two are from same Artist and different Albums from different Artists.
  • One song can be sung/written/shared by one or more Artists as well.
  • One Song can be in many Albums sung/written by one or more Artists.
  • One Album contains many Songs sung/written by different Artists.

How RESTRICTS works:

Now, in real world, if we have to delete the Artist all his Albums and Songs in Albums should be deleted. But, only when all the songs in his Albums doesn't share relationship with other artists. In other words, when all songs referenced to the same Artist, then deletion of Artist, Albums and Songs will happen.

Note that we can't delete artist_two, because song_two shared his album_two along with artist_one.

In simple words, in Song object, if artist and artist from the album are same, RESTRICT allows to delete.

Siva Sankar
  • 1,672
  • 1
  • 9
  • 16
0

by taking @Roham example

class Artist(models.Model):
    name = models.CharField(max_length=10)

class Album(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)

class Song(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    album = models.ForeignKey(Album, on_delete=models.RESTRICT)

So here RESTRICT and PROTECT are suppose to stop the deletion of a Album instance that is referenced in a song instance. But in case of a special case, only RESTRICT will allow to delete the album instance such that instance of artist should also be deleted simultaneously (artist reference should be same for both album and song). If you will use PROTECT, it will protect deletion anyway. I hope this simple explanation helps you.

Som Dixit
  • 21
  • 3
0

The short answer in simple words is:

CASCADE by deletion of parent, child also gets deleted.

SET_NULL lets parent be deleted but keeps the child.

PROTECT never lets the deletion of parent to deletion of child.

while RESTRICT allows deletion of child only if all of its owners(parents) are deleted in past or currently are being deleted (makes sure other instances are not involved).

Farhang Amaji
  • 742
  • 11
  • 24