PROTECT против RESTRICT для on_delete (Django)

Я прочитал документацию django о PROTECT и RESTRICT для использования с "on_delete".

  • ЗАЩИТА

Предотвратить удаление объекта, на который ссылается ссылка, вызвав ProtectedError, подкласс django.db.IntegrityError. подкласс django.db.IntegrityError.

Пример:

class MyModel(models.Model):
    field = models.ForeignKey(YourModel, on_delete=models.PROTECT)
  • ОГРАНИЧЕНИЕ

Предотвратить удаление объекта, на который ссылается ссылка, вызвав RestrictedError (подкласс django.db.IntegrityError). В отличие от PROTECT, удаление ссылающегося объекта разрешается, если он также ссылается на другой объект, который удаляется в той же операции, но через отношение CASCADE. связь.

Пример:

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

В какой-то степени я понимаю разницу между PROTECT и RESTRICT, но не совсем, так в чем же разница между PROTECT и RESTRICT? и когда я должен их использовать?

Согласно документации Django RESTRICT позволяет вам удалять ссылающийся объект в некоторых особых ситуациях. Например:

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)

Как видите, если вы создадите экземпляр альбома и после этого создадите экземпляр песни с тем же исполнителем (теперь у вас есть песня и альбом с тем же исполнителем), то вы можете просто удалить этого исполнителя без каких-либо проблем (поскольку в этой операции удаления вы также удаляете связанные объекты. Также обратите внимание, что у исполнителя есть CASCADE при удалении песни и альбома). Но если вы определили PROTECT вместо RESTRICT, например:

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

вы не могли удалить экземпляр исполнителя, потому что на него ссылается эта песня. Если вы спросите меня, я бы сказал, что RESTRICT - это другая версия PROTECT с меньшими ограничениями на удаление объекта. Если это объяснение пока не понятно, я бы порекомендовал вам сам пример Django:

Артист может быть удален, даже если это подразумевает удаление Альбома, на который ссылается Песня, потому что Песня также ссылается на Артиста через каскадные отношения. Например:

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

Вызывает RestrictedError.

artist_two.delete()

Вызывает RestrictedError.

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

Успешно удалит ваш объект

Использование различных типов on_delete действительно связано с вашим дизайном и вашими ограничениями на удаление объектов. Итак, в основном, когда вы хотите просто защитить свой объект от удаления (без каких-либо зависимостей), использование PROTECT является лучшим решением, потому что при использовании RESTRICT в этом случае вы заставляете Django искать в каждом связанном объекте (вложенный цикл поиска) для проверки, будут ли другие отношения удалены в этом процессе или нет, и это может плохо сказаться на производительности удаления.

на примере @Roham

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 и PROTECT должны остановить удаление экземпляра альбома, на который ссылается экземпляр песни. Но в особом случае, только RESTRICT позволит удалить экземпляр альбома так, что экземпляр исполнителя также должен быть удален одновременно (ссылка на исполнителя должна быть одинаковой для альбома и песни). Если вы будете использовать PROTECT, он в любом случае защитит удаление. Надеюсь, это простое объяснение поможет вам.

Исходя из требований реальных приложений, мы используем оба варианта для разных целей.

PROTECT никогда не удаляет и выдает ошибку. Но, RESTRICT (введенный в Django 3.1) удаляет в некоторых случаях, а не во всех.

PROTECT пример: Согласно как предотвратить удаление,

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 объяснение: Думайте с точки зрения реального мира. Будет много Employee и Employee может иметь несколько Project. Если мы удалим Employee, если у него есть несколько Project, связанных с ним, то объекты проекта в модели Project останутся. Это неверно. Если Employee сделал несколько Project, он (объект Employee) не может быть удален. Поэтому мы использовали PROTECT. Это будет работать для предотвращения удаления любого объекта Employee, который имеет один или несколько связанных с ним объектов Project.

Вам нужно сначала понять CASCADE, прежде чем понять RESTRICT:

CASCADE пример:

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

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

CASCADE объяснение: Думайте с точки зрения реального мира. Существует множество Artist и Artist может иметь несколько Album. Если мы хотим удалить Artist и связанные с ним Album, мы используем CASCADE. Помните, CASCADE удаляет. Он всегда удаляет.

RESTRICT пример:

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 объяснение: Теперь подумайте еще раз с точки зрения реального мира. У Artist будет ноль или больше Album. У Album может быть ноль или больше Song. Нет никакой проблемы в удалении, если Artist имеет ноль Album и Album имеет ноль Song. Фактически, нет никакой связи, поскольку Artist вообще не имеет никаких Album. Проблема удаления возникает, и сценарий начинается, когда Artist имеет несколько Album, а Album имеет несколько Song. Вот как:

RESTRICT и PROTECT работают одинаково. Но PROTECT состоит из двух шагов. Родительский и Дочерний. Если мы не должны удалять Дочь (Album), мы не должны удалять Родителя (Artist). Другими словами, мы используем PROTECT, если не хотим, чтобы наш Дочь (Album) был удален, если удален Родитель (Artist). PROTECT защищает от удаления объектов.

И, RESTRICT состоит из трех ступеней. Родитель, ребенок и внук. RESTRICT (ограничивающее условие или мера) ограничивает удаление объектов только до определенного предела.

Вам нужно понять реальный сценарий, почему мы используем RESTRICT. Допустим, есть несколько Artist. Каждый Artist имеет несколько Album. Каждый Album имеет несколько song. см. следующий код

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

Обратите внимание, что из приведенного выше кода,

  • song_one и song_two - от одного и того же Artist, а разные Album - от разных Artist.
  • Один song может быть воспет/записан/разделен одним или более Artists также.
  • Один Song может быть во многих Album воспетых/записанных одним или более Artists.
  • Один Album содержит много Song, написанных разными Artists.

Как работает RESTRICTS:

Теперь, в реальном мире, если мы должны удалить Artist, все его Album и Song в Album должны быть удалены. Но, только если все песни в его Albums не имеют общих отношений с другими artists. Другими словами, когда все песни относятся к одному и тому же Artist, тогда удаление Artist, Album и Song произойдет.

Обратите внимание, что мы не можем удалить artist_two, потому что song_two поделился своим album_two вместе с artist_one.

Проще говоря, в объекте Song, если artist и artist из альбома одинаковы, RESTRICT позволяет удалить.

Короткий ответ в простых словах таков:

CASCADE при удалении родителя удаляется и ребенок.

SET_NULL позволяет удалить родителя, но сохранить ребенка.

PROTECT никогда не позволяет удалять родителя OF ребенка.

<
Вернуться на верх