что делает on delete на моделях Django?

Я довольно хорошо знаком с Django, но недавно заметил, что существует on_delete=models.CASCADE вариант с моделями, я искал документацию для того же самого, но не мог найти ничего больше, чем,

изменено в Django 1.9:

on_delete теперь можно использовать в качестве второго позиционного аргумента (ранее он обычно передавался только как аргумент ключевого слова). Это будет обязательный аргумент в Django 2.0.

an пример использования

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

что делает on_delete? (угадайте действия, которые необходимо выполнить, если модель удалена)

что делает модели.Каскад сделать? (любые подсказки в документации)

какие еще варианты доступны (если моя догадка верна)?

где находится документация для этого?

5 ответов


это поведение, чтобы принять, когда ссылка "объект" удаляется. Это не специфично для django, это стандарт SQL.

есть 6 возможных действий, чтобы предпринять, когда такое событие происходит:

  • CASCADE: при удалении объекта, на который есть ссылка, также удалите объекты, на которые есть ссылки (например, при удалении сообщения в блоге вы также можете удалить комментарии). Эквивалент SQL: CASCADE.
  • PROTECT: запретить удаление объекта. Чтобы удалить его, вам придется удалить все объекты, которые ссылаются на него вручную. Эквивалентом SQL: RESTRICT.
  • SET_NULL: установите ссылку на NULL (требуется, чтобы поле было nullable). Например, когда вы удаляете пользователя, вы можете сохранить комментарии, которые он опубликовал в блогах, но сказать, что он был опубликован анонимным (или удаленным) пользователем. Эквивалентом SQL: SET NULL.
  • SET_DEFAULT: установить значение по умолчанию. Эквивалентом SQL: SET DEFAULT.
  • SET(...): установить заданное значение. Это не является частью стандарта SQL и полностью обрабатывается Django.
  • DO_NOTHING: вероятно, очень плохая идея, так как это создаст проблемы с целостностью в вашей базе данных (ссылаясь на объект, который на самом деле не существует). Эквивалентом SQL: NO ACTION.

источник: документация Django

см. также документация В PostgreSQL например.

в большинстве случаев, CASCADE это ожидаемое поведение, но для каждого ForeignKey вы всегда должны спросить себя, что такое ожидаемое поведение в этой ситуации. PROTECT и SET_NULL часто полезны. Настройка CASCADE где это не должно, потенциально может удалить всю вашу базу данных в каскаде, просто удалив одного пользователя.


на on_delete метод используется, чтобы сказать Django, что делать с экземплярами модели, которые зависят от экземпляра модели, который вы удаляете. (например, a ForeignKey отношения). The on_delete=models.CASCADE говорит Django каскадировать эффект удаления, т. е. продолжить удаление зависимых моделей.

вот более конкретный пример. Предположим, у вас есть Author модель, которая является ForeignKey на Book модель. Теперь, если вы удалите экземпляр Author модель, Django не знал бы, что делать с примеры Book модель, которая зависит от этого экземпляра Author - модели. The on_delete метод говорит Django, что делать в этом случае. Настройка on_delete=models.CASCADE проинструктирует Django каскадировать эффект удаления, т. е. удалить все Book экземпляры модели, которые зависят от Author экземпляр модели, который вы удалили.

Примечание: on_delete станет обязательным аргументом в Django 2.0. В более старых версиях по умолчанию CASCADE.

вот весь официальная документация.


FYI, параметр on_delete в моделях обратно от того, как это звучит. Вы ставите "on_delete" на внешний ключ (FK) на модели, чтобы сказать django, что делать, если запись FK, на которую вы указываете в своей записи, удалена. Варианты, которые наш магазин использовал больше всего, - PROTECT, CASCADE и SET_NULL. Вот основные правила, которые я придумал:--2-->

  1. используйте PROTECT, когда ваш FK указывает на таблицу поиска, которая действительно не должна меняться и что конечно не должно привести к изменению таблицы. Если кто-то пытается удалить запись в этой таблице поиска, PROTECT не позволяет удалить ее, если она привязана к каким-либо записям. Это также предотвращает удаление django код запись только потому, что он удалил запись в таблице. Эта последняя часть имеет решающее значение. если кто-то должен был удалить Пол "Женский" из моей гендерной таблицы, я, конечно, не хотел бы, чтобы мгновенно удалить всех людей, которых я имел в мой личный стол, у которого был этот пол.
  2. используйте каскад, когда ваш FK указывает на" родительскую " запись. Итак, если у человека может быть много записей PersonEthnicity (он может быть американским индейцем, черным и белым), и этот человек is удалил, я действительно люблю!--5-->б хотите, чтобы любые" дочерние " записи PersonEthnicity были удалены. Они не имеют значения без человека.
  3. используйте SET_NULL, когда вы do хотите, чтобы людям было разрешено удалять запись в таблице поиска, но вы все равно хотите сохранить свою запись. Например, если человек может иметь среднюю школу, но для меня не имеет значения, уходит ли эта средняя школа на мой поисковый стол, я бы сказал: "on_delete=SET_NULL."Это оставило бы мой личный рекорд там; это просто установило бы школьный FK на моем лице в нуль. Очевидно, вам придется разрешить null=True на этом FK.

вот пример модели, которая делает все три вещи:

class PurchPurchaseAccount(models.Model):
    id = models.AutoField(primary_key=True)
    purchase = models.ForeignKey(PurchPurchase, null=True, db_column='purchase', blank=True, on_delete=models.CASCADE) # If "parent" rec gone, delete "child" rec!!!
    paid_from_acct = models.ForeignKey(PurchPaidFromAcct, null=True, db_column='paid_from_acct', blank=True, on_delete=models.PROTECT) # Disallow lookup deletion & do not delete this rec.
    _updated = models.DateTimeField()
    _updatedby = models.ForeignKey(Person, null=True, db_column='_updatedby', blank=True, related_name='acctupdated_by', on_delete=models.SET_NULL) # Person records shouldn't be deleted, but if they are, preserve this PurchPurchaseAccount entry, and just set this person to null.

    def __unicode__(self):
        return str(self.paid_from_acct.display)
    class Meta:
        db_table = u'purch_purchase_account'

как последний лакомый кусочек, вы знали, что если вы не укажите on_delete (или нет), поведение по умолчанию-CASCADE? Это означает, что если кто-то удалил гендерную запись в вашей гендерной таблице, записи любого человека с этим полом также были удалены!

Я бы сказал: "Если есть сомнения, установите on_delete=models.ЗАЩИЩАТЬ.- Тогда иди проверь свое заявление. Вы быстро поймете, какие FKs должны быть помечены другими значениями, не подвергая опасности ваших данных.

кроме того, стоит отметить, что on_delete=CASCADE фактически не добавляется ни к одной из ваших миграций, если это поведение, которое вы выбираете. Я думаю, это потому, что это значение по умолчанию, поэтому установка on_delete=CASCADE-это то же самое, что ничего не ставить.


вот ответ на ваш вопрос, который говорит: Почему мы используем on_delete?

при удалении объекта, на который ссылается ForeignKey, Django по умолчанию эмулирует поведение ограничения SQL на delete CASCADE, а также удаляет объект, содержащий ForeignKey. Это поведение можно переопределить, указав аргумент on_delete. Например, если у вас есть Nullable ForeignKey и вы хотите, чтобы он был установлен null, когда ссылочный объект исключено:

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

возможные значения для on_delete находятся в django.децибел.модели:

каскад: Cascade удаляет; по умолчанию.

защита: предотвратите удаление ссылочного объекта, подняв ProtectedError, подкласс django.децибел.IntegrityError.

SET_NULL: установите значение ForeignKey null; это возможно, только если значение null равно True.

SET_DEFAULT: установить значение ForeignKey по умолчанию; значение по умолчанию для ForeignKey должно быть установлено.


как упоминалось ранее, CASCADE удалит запись с внешним ключом и ссылается на другой объект, который был удален. Так, например, если у вас есть сайт недвижимости и есть свойство, которое ссылается на город

class City(models.Model):
    # define model fields for a city

class Property(models.Model):
    city = models.ForeignKey(City, on_delete = models.CASCADE)
    # define model fields for a property

и теперь, когда город удален из базы данных, все связанные свойства (например. недвижимость, расположенная в этом городе) также будет удалена из базы данных

Теперь я также хочу упомянуть о достоинствах других вариантов, таких как SET_NULL или SET_DEFAULT или даже DO_NOTHING. В принципе, с точки зрения администрирования вы хотите "удалить" эти записи. Но ты же не хочешь, чтобы они исчезли. По многим причинам. Кто-то мог случайно удалить его или для аудита и мониторинга. И простой отчет. Таким образом, это может быть способ "отключить" собственность от города. Опять же, это будет зависеть от того, как приложение написано.

например, некоторые приложения имеют поле "удалено", которое равно 0 или 1. И все их поиск и просмотры списка и т. д., Все, что может отображаться в отчетах или в любом месте, к которому пользователь может получить доступ с переднего конца, исключают все, что deleted == 1. Однако, если вы создаете пользовательский отчет или пользовательский запрос, чтобы вытащить список записей, которые были удалены, и тем более увидеть, когда он был последний раз изменен (другое поле) и кем (т. е. кто удалил его и когда)..это очень выгодно с точки зрения исполнительной власти.

и не забывайте, что вы можете отменить случайное удаление так же просто, как deleted = 0 для тех записей.

моя точка зрения, если есть функциональность, всегда есть причина. Не всегда веская причина. Но причина. И часто хороший.