it-swarm.com.ru

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

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

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

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

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

from Django.db import models

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

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

Что делает on_delete? ( Я предполагаю действия, которые нужно выполнить, если модель удалена )

Что делает models.CASCADE? ( любые подсказки в документации )

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

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

211
Marty

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

Существует 6 возможных действий при возникновении такого события:

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

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

Смотрите также документация PostGreSQL например.

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

417
Antoine Pinsard

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

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

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

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

33
Himank Yadav

К сведению, параметр on_delete в моделях обратен тому, на что он похож. Вы помещаете "on_delete" в внешний ключ (FK) в модели, чтобы сообщить Django, что делать, если удаленная запись FK, на которую вы указываете в своей записи. В нашем магазине больше всего вариантов: PROTECT, CASCADE и SET_NULL. Вот основные правила, которые я выяснил:

  1. Используйте PROTECT, когда ваш FK указывает на справочную таблицу, которая на самом деле не должна меняться и которая конечно не должна вызывать изменения вашей таблицы. Если кто-либо пытается удалить запись в этой справочной таблице, PROTECT не позволяет удалить ее, если она связана с какими-либо записями. Он также не позволяет Django удалять вашу запись только потому, что он удалил запись в справочной таблице. Эта последняя часть имеет решающее значение. Если бы кто-то удалил пол "Женщина" из моей таблицы "Гендер", Я бы НЕ хотел, чтобы это мгновенно удаляло всех и всех людей, которые были у меня в таблице "Персона", у которых был этот пол.
  2. Используйте CASCADE, когда ваш FK указывает на "родительскую" запись. Итак, если у человека может быть много записей PersonEthnicity (он/она может быть американским индейцем, черным и белым), и этот человек удален удален, я действительно хотел бы хочу любой "Дочерние" записи PersonEthnicity должны быть удалены. Они не имеют отношения к личности.
  3. Используйте SET_NULL, когда вы делаете хотите, чтобы людям было разрешено удалить запись в справочной таблице, но вы все равно хотите сохранить свою запись. Например, если у человека может быть старшая школа, но для меня не имеет значения, исчезнет ли эта старшая школа из моей справочной таблицы, я бы сказал "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.PROTECT." Тогда иди протестируй свое приложение. Вы быстро выясните, какие FK должны быть помечены другими значениями, не подвергая опасности какие-либо ваши данные.

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

25
HelenM

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

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

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

Возможные значения on_delete находятся в Django.db.models:

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

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

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

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

3
Sonia Rani

Как упоминалось ранее, 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 для этих записей.

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

3
George Mogilevsky