Znam Django, ale ostatnio zauważyłem, że istnieje on_delete=models.CASCADE
opcja dla modeli, szukałem dokumentacji dla tego samego, ale nie mogłem znaleźć nic więcej niż:
Zmieniono w Django 1.9:
on_delete
może być teraz używany jako drugi argument pozycyjny (wcześniej był zwykle przekazywany tylko jako argument słowa kluczowego). Będzie to wymagany argument w Django 2.0.
przykładowy przypadek użycia to
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
Co robi on_delete? ( Myślę, że działania, które należy wykonać, jeśli model zostanie usunięty )
Co ma models.CASCADE
zrobić? ( wszelkie wskazówki w dokumentacji )
Jakie inne opcje są dostępne ( jeśli moje przypuszczenie jest prawidłowe )?
Gdzie znajduje się dokumentacja do tego?
python
django
django-models
Wszystko to
źródło
źródło
Odpowiedzi:
Takie zachowanie należy zastosować po usunięciu obiektu, do którego istnieje odwołanie . Nie jest specyficzny dla django, jest to standard SQL.
W przypadku wystąpienia takiego zdarzenia można podjąć 6 działań:
CASCADE
: Po usunięciu obiektu, do którego istnieje odwołanie, usuń także obiekty, które mają do niego odniesienia (np. Po usunięciu posta na blogu możesz również usunąć komentarze). SQL równoważne:CASCADE
.PROTECT
: Zabroń usuwania obiektu, do którego istnieje odwołanie. Aby go usunąć, musisz usunąć wszystkie obiekty, które odnoszą się do niego ręcznie. SQL równoważne:RESTRICT
.SET_NULL
: Ustaw odwołanie na NULL (wymaga, aby pole było nullable). Na przykład, gdy usuwasz użytkownika, możesz chcieć zachować komentarze, które opublikował na blogach, ale powiedz, że zostały opublikowane przez anonimowego (lub usuniętego) użytkownika. SQL równoważne:SET NULL
.SET_DEFAULT
: Ustaw wartość domyślną. SQL równoważne:SET DEFAULT
.SET(...)
: Ustaw określoną wartość. Ten nie jest częścią standardu SQL i jest w całości obsługiwany przez Django.DO_NOTHING
: Prawdopodobnie bardzo zły pomysł, ponieważ spowodowałoby to problemy z integralnością w bazie danych (odwoływanie się do obiektu, który tak naprawdę nie istnieje). SQL równoważne:NO ACTION
.Źródło: dokumentacja Django
Zobacz także na przykład dokumentację PostGreSQL .
W większości przypadków
CASCADE
jest to oczekiwane zachowanie, ale dla każdego klucza zagranicznego należy zawsze zadać sobie pytanie, jakie jest oczekiwane zachowanie w tej sytuacji.PROTECT
iSET_NULL
często są przydatne. UstawienieCASCADE
tam, gdzie nie powinno, może potencjalnie kasować całą bazę danych kaskadowo, po prostu usuwając pojedynczego użytkownika.Dodatkowa uwaga wyjaśniająca kierunek kaskady
Zabawnie jest zauważyć, że
CASCADE
dla wielu osób kierunek działania nie jest jasny. Właściwie, to zabawne zauważyć, że tylkoCASCADE
działanie nie jest jasne. Rozumiem, że zachowanie kaskady może być mylące, jednak musisz myśleć, że jest to ten sam kierunek, co każde inne działanie . Zatem jeśli uważasz, że tenCASCADE
kierunek nie jest dla ciebie jasny, w rzeczywistości oznacza to, żeon_delete
zachowanie nie jest dla ciebie jasne.W bazie danych klucz obcy jest zasadniczo reprezentowany przez pole liczby całkowitej, którego wartość jest kluczem podstawowym obiektu obcego. Załóżmy, że masz wpis comment_A , który ma obcy klucz do wpisu article_B . Jeśli usuniesz wpis komentarz_A , wszystko jest w porządku, artykuł_B żył bez komentarza_A i nie przejmuj się, jeśli zostanie usunięty. Jednakże, jeśli usuniesz article_B , następnie comment_A paniki! Nigdy nie żył bez article_B i potrzebuje go, jest częścią jego atrybutów (
article=article_B
ale czym jest * article_B ** ???). Tutajon_delete
wkracza, aby ustalić, jak rozwiązać ten błąd integralności, albo mówiąc:PROTECT
w języku SQL)SET_NULL
)CASCADE
zachowanie).SET_DEFAULT
a nawetSET(...)
).DO_NOTHING
)Mam nadzieję, że dzięki temu kierunek kaskady będzie wyraźniejszy. :)
źródło
Comment
ma klucz obcy, abyBlogPost
usunąć BlogPost powinien usunąć komentarz, ale usunięcie komentarza nie powinno usunąć BlogPost, niezależnie od RDMS?Comment
, kto ma pole FK w swojej tabeli, aBlogPost
„jest właścicielem”,Comment
jeśli mówimy o modelu z prawdziwego życia. Dobrze.Ta
on_delete
metoda służy do poinformowania Django, co zrobić z instancjami modelu zależnymi od usuniętej instancji modelu. (np.ForeignKey
związek).on_delete=models.CASCADE
Informuje Django kaskadowy efekt kasowania tj kontynuować usuwanie modeli zależnych, jak również.Oto bardziej konkretny przykład. Załóżmy, że masz
Author
modelForeignKey
wBook
modelu. Teraz, jeśli usuniesz instancjęAuthor
modelu, Django nie będzie wiedział, co zrobić z instancjamiBook
modelu zależnymi od tej instancjiAuthor
modelu. Taon_delete
metoda mówi Django, co należy zrobić w takim przypadku. Ustawienieon_delete=models.CASCADE
instruuje Django, aby kaskadowo usunąć efekt, tzn. Usunąć wszystkieBook
instancje modelu, które zależą odAuthor
usuniętej instancji modelu.Uwaga:
on_delete
stanie się wymaganym argumentem w Django 2.0. W starszych wersjach domyślnie jest toCASCADE
.Oto cała oficjalna dokumentacja.
źródło
Do Twojej wiadomości,
on_delete
parametr w modelach jest odwrócony od tego, jak to brzmi. Umieszczaszon_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
iSET_NULL
. Oto podstawowe zasady, które wymyśliłem: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ć.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.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łbymon_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:
Jako ostatnią ciekawostkę, czy wiesz, że jeśli nie określisz
on_delete
(lub nie określisz ), zachowanie domyślne toCASCADE
? 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 stawianieon_delete=CASCADE
jest tym samym, co stawianie niczego.źródło
Jak wspomniano wcześniej, CASCADE usunie rekord zawierający klucz obcy i odniesie się do innego obiektu, który został usunięty. Na przykład, jeśli masz witrynę z nieruchomościami i masz nieruchomość, która odwołuje się do miasta
a teraz, gdy miasto zostanie usunięte z bazy danych, wszystkie powiązane nieruchomości (np. nieruchomości znajdujące się w tym mieście) również zostaną usunięte z bazy danych
Teraz chcę również wspomnieć o zaletach innych opcji, takich jak SET_NULL lub SET_DEFAULT, a nawet DO_NOTHING. Zasadniczo z administracyjnego punktu widzenia chcesz „usunąć” te rekordy. Ale tak naprawdę nie chcesz, żeby zniknęły. Z wielu powodów. Ktoś mógł usunąć go przypadkowo lub w celu przeprowadzenia audytu i monitorowania. I proste raportowanie. Może to być sposób na „odłączenie” nieruchomości od miasta. Znowu będzie to zależeć od sposobu pisania aplikacji.
Na przykład niektóre aplikacje mają pole „usunięte”, które wynosi 0 lub 1. Wszystkie wyszukiwania i widoki list itp., Wszystko, co może pojawiać się w raportach lub gdziekolwiek użytkownik może uzyskać do nich dostęp z interfejsu użytkownika, wykluczają wszystko, co jest
deleted == 1
. Jeśli jednak utworzysz raport niestandardowy lub zapytanie niestandardowe, aby rozwinąć listę rekordów, które zostały usunięte, a nawet więcej, aby zobaczyć, kiedy była ostatnio modyfikowana (inne pole) i przez kogo (tj. Kto ją usunął i kiedy). jest to bardzo korzystne z wykonawczego punktu widzenia.I nie zapominaj, że możesz przywrócić przypadkowe usunięcie tak proste, jak w
deleted = 0
przypadku tych rekordów.Chodzi mi o to, że jeśli jest jakaś funkcjonalność, zawsze ma to jakiś powód. Nie zawsze jest to dobry powód. Ale powód. I często też dobry.
źródło
Oto odpowiedź na pytanie, która brzmi: dlaczego używamy on_delete?
Po usunięciu obiektu, do którego odwołuje się ForeignKey, Django domyślnie emuluje zachowanie ograniczenia SQL NA USUŃ KASKADĘ, a także usuwa obiekt zawierający klucz zagraniczny. To zachowanie można zastąpić, podając argument on_delete. Na przykład, jeśli masz zerowalny klucz obcy i chcesz, aby był ustawiony na null po usunięciu obiektu odniesienia:
Możliwe wartości dla on_delete znajdują się w django.db.models:
KASKADA: Kaskada jest usuwana; domyślny.
PROTECT: Zapobiegaj usuwaniu obiektu, do którego istnieje odwołanie, podnosząc ProtectedError, podklasę django.db.IntegrityError.
SET_NULL: Ustaw wartość ForeignKey na wartość null; jest to możliwe tylko wtedy, gdy null ma wartość True.
SET_DEFAULT: Ustaw wartość klucza obcego na wartość domyślną; należy ustawić wartość domyślną dla klucza obcego.
źródło
Załóżmy, że masz dwa modele, jeden o nazwie Osoba, a drugi o nazwie Firmy .
Z definicji jedna osoba może utworzyć więcej niż jedną firmę.
Biorąc pod uwagę, że firma może mieć jedną i tylko jedną osobę, chcemy, aby po usunięciu osoby usunąć wszystkie firmy powiązane z tą osobą.
Zaczynamy od utworzenia takiego modelu osoby
Wtedy model firm może wyglądać tak
Zwróć uwagę na użycie
on_delete=models.CASCADE
w modelu Firmy. Oznacza to usunięcie wszystkich firm po usunięciu osoby, która jest jej właścicielem (instancja klasy Osoba).źródło
Zmień orientację swojego modelu mentalnego na funkcjonalność „KASKADY”, myśląc o dodaniu FK do już istniejącej kaskady (np. Wodospadu). Źródłem tego wodospadu jest Klucz Podstawowy. Usuwa spływ.
Więc jeśli zdefiniujesz on_delete FK jako „CASCADE”, dodajesz ten rekord FK do kaskady usuwania pochodzących z PK. Rekord FK może uczestniczyć w tej kaskadzie lub nie („SET_NULL”). W rzeczywistości zapis z FK może nawet uniemożliwić przepływ operacji usuwania! Zbuduj tamę za pomocą „PROTECT”.
źródło
Użycie KASKADY oznacza, że faktycznie nakazuje Django, aby usunął odnośny rekord. W poniższym przykładzie aplikacji do ankiety: usunięcie „pytania” spowoduje również usunięcie opcji, które ma to pytanie.
np. pytanie: jak się o nas dowiedziałeś? (Wybory: 1. Znajomi 2. Reklama telewizyjna 3. Wyszukiwarka 4. Promocja e-mail)
Usunięcie tego pytania spowoduje również usunięcie wszystkich czterech opcji z tabeli. Zauważ, w którym kierunku płynie. Nie musisz umieszczać parametru on_delete = models.CASCADE w Modelu pytań umieść go w opcji Wybór.
źródło