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