FYI, on_delete
параметр у моделях відхилений від того, як він звучить. Ви надягаєте on_delete
зовнішню клавішу (FK) на модель, щоб повідомити django, що робити, якщо запис FK, на який ви вказуєте у своєму записі, буде видалений. Варіанти нашого магазину використовували більшість з них PROTECT
, CASCADE
і SET_NULL
. Ось основні правила, які я з'ясував:
- Використовуйте,
PROTECT
коли ваш FK вказує на оглядову таблицю, яка насправді не повинна змінюватися і яка, безумовно, не повинна спричиняти зміни вашої таблиці. Якщо хтось намагається видалити запис із цієї таблиці пошуку, PROTECT
не дозволяє їм видалити його, якщо він прив’язаний до будь-яких записів. Він також не дозволяє django видалити ваш запис лише тому, що він видалив запис із таблиці пошуку. Ця остання частина є критичною. Якби хтось видалив гендерну групу "Жінки" з моєї гендерної таблиці, Я НАРОДНО НЕ хотів би, щоб миттєво видаляв усіх людей, які були в моїй таблиці Особи, які мали цю стать.
- Використовуйте,
CASCADE
коли ваш FK вказує на запис "батьків". Отже, якщо у Особи може бути багато записів PersonEthnicity (він / вона може бути американським індіанцем, чорним і білим), і ця особа буде видалена, я дуже хотів би видалити будь-які "дитячі" записи PersonEthnicity. Вони не мають значення без Особи.
- Використовуйте ,
SET_NULL
якщо ви дійсно хочете , щоб люди , щоб мати можливість видалити запис на довідкову таблицю, але ви все ще хочете зберегти запис. Наприклад, якщо людина може мати середню школу, але це не дуже важливо для мене, якщо ця гімназія піде на мій оглядовий стіл, я б сказав on_delete=SET_NULL
. Це залишило б мою особу запису там; це просто встановить нульову школу ФК на моїй Особі на нуль. Очевидно, вам доведеться дозволити null=True
в цьому ФК.
Ось приклад моделі, яка виконує всі три речі:
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
". Потім перейдіть на тестування своєї заявки. Ви швидко зрозумієте, на яких ФК слід позначати інші значення, не загрожуючи жодним вашим даним.
Також варто зауважити, що on_delete=CASCADE
насправді не додається до жодної вашої міграції, якщо це така поведінка, яку ви обираєте. Я думаю, це тому, що це за замовчуванням, тому ставити on_delete=CASCADE
те саме, що нічого не ставити.