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
может быть воспет/записан/разделен одним или болееArtist
s также. - Один
Song
может быть во многихAlbum
воспетых/записанных одним или болееArtist
s. - Один
Album
содержит многоSong
, написанных разнымиArtist
s.
Как работает RESTRICTS
:
Теперь, в реальном мире, если мы должны удалить Artist
, все его Album
и Song
в Album
должны быть удалены. Но, только если все песни в его Album
s не имеют общих отношений с другими artist
s. Другими словами, когда все песни относятся к одному и тому же Artist
, тогда удаление Artist
, Album
и Song
произойдет.
Обратите внимание, что мы не можем удалить artist_two
, потому что song_two
поделился своим album_two
вместе с artist_one
.
Проще говоря, в объекте Song, если artist
и artist
из альбома одинаковы, RESTRICT позволяет удалить.
Короткий ответ в простых словах таков:
CASCADE
при удалении родителя удаляется и ребенок.
SET_NULL
позволяет удалить родителя, но сохранить ребенка.
PROTECT
никогда не позволяет удалять родителя OF ребенка.