Do Twojej wiadomości, on_delete
parametr w modelach jest odwrócony od tego, jak to brzmi. Umieszczasz on_delete
na modelu klucz obcy (FK), aby powiedzieć django, co zrobić, jeśli pozycja FK, na którą wskazujesz w swoim rekordzie, zostanie usunięta. Options nasz sklep zostały wykorzystane najbardziej są PROTECT
, CASCADE
i SET_NULL
. Oto podstawowe zasady, które wymyśliłem:
- Użyj,
PROTECT
gdy twój FK wskazuje na tablicę przeglądową, która tak naprawdę nie powinna się zmieniać i która z pewnością nie powinna powodować zmiany tabeli. Jeśli ktoś spróbuje usunąć wpis z tej tabeli przeglądowej, PROTECT
uniemożliwia mu usunięcie wpisu, jeśli jest on powiązany z dowolnymi rekordami. To także zapobiega django z usunięciem swój rekord tylko dlatego, że usunięty wpis w tabeli przeglądowej. Ta ostatnia część jest krytyczna. Gdyby ktoś usunął płeć „Kobieta” z mojej tabeli Płeć, NA PEWNO NIE chciałbym, aby natychmiast usunęła wszystkie osoby, które miałem w mojej Tabeli osób, które miały tę płeć.
- Użyj,
CASCADE
gdy twój FK wskazuje na rekord „nadrzędny”. Tak więc, jeśli Osoba może mieć wiele wpisów PersonEnicnicity (może być Indianinem, Czarnym i Białym), a ta Osoba zostanie usunięta, naprawdę chciałbym, aby wszelkie „Personalne” wpisy PersonEnicnicity zostały usunięte. Są bez znaczenia bez Osoby.
- Użyj,
SET_NULL
gdy chcesz , aby ludzie mogli usuwać wpis z tabeli przeglądowej, ale nadal chcesz zachować swój zapis. Na przykład, jeśli osoba może mieć liceum, ale tak naprawdę nie ma dla mnie znaczenia, czy liceum odejdzie na moim stole przeglądowym, powiedziałbym on_delete=SET_NULL
. W ten sposób moja Osoba zostanie tam zapisana; po prostu ustawiłoby FK dla mojej szkoły na mojej osobie na zero. Oczywiście będziesz musiał pozwolić null=True
na to FK.
Oto przykład modelu, który wykonuje wszystkie trzy czynności:
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'
Jako ostatnią ciekawostkę, czy wiesz, że jeśli nie określisz on_delete
(lub nie określisz ), zachowanie domyślne to CASCADE
? Oznacza to, że jeśli ktoś usunie wpis dotyczący płci w tabeli Płeć, wszelkie rekordy Osoby tej płci również zostaną usunięte!
Powiedziałbym: „W razie wątpliwości ustaw on_delete=models.PROTECT
”. Następnie przetestuj swoją aplikację. Szybko zorientujesz się, które FK powinny być oznaczone innymi wartościami, nie zagrażając żadnym z twoich danych.
Warto również zauważyć, że on_delete=CASCADE
tak naprawdę nie jest dodawane do żadnej z migracji, jeśli takie zachowanie wybierzesz. Myślę, że dzieje się tak, ponieważ jest to ustawienie domyślne, więc stawianie on_delete=CASCADE
jest tym samym, co stawianie niczego.