Ich kenne Django ziemlich gut, habe aber kürzlich festgestellt, dass es eine on_delete=models.CASCADE
-Option für die Modelle gibt. Ich habe nach der gleichen Dokumentation gesucht, konnte aber nichts weiter finden als:
Geändert in Django 1.9:
on_delete
kann jetzt als zweites Positionsargument verwendet werden (zuvor wurde es normalerweise nur als Schlüsselwortargument übergeben). Es wird ein erforderliches Argument in Django 2.0 sein.
from Django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
Was macht on_delete? ( Ich schätze, was zu tun ist, wenn das Modell gelöscht wird )
Was macht models.CASCADE
? ( Hinweise in der Dokumentation )
Welche anderen Optionen stehen zur Verfügung (, wenn meine Vermutung richtig ist )?
Wo befindet sich die Dokumentation dazu?
Dies ist das Verhalten, das angewendet werden soll, wenn das referenzierte Objekt gelöscht wird. Es ist nicht spezifisch für Django, dies ist ein SQL-Standard.
Es gibt 6 mögliche Aktionen, die ausgeführt werden müssen, wenn ein solches Ereignis eintritt:
CASCADE
: Wenn das Objekt, auf das verwiesen wird, gelöscht wird, löschen Sie auch die Objekte, auf die verwiesen wird. (Wenn Sie beispielsweise einen Blogbeitrag entfernen, möchten Sie möglicherweise auch Kommentare löschen.) SQL-Äquivalent: CASCADE
.PROTECT
: Verbietet das Löschen des referenzierten Objekts. Um es zu löschen, müssen Sie alle Objekte, die darauf verweisen, manuell löschen. SQL-Äquivalent: RESTRICT
.SET_NULL
: Setzen Sie den Verweis auf NULL (das Feld muss nullwertfähig sein). Wenn Sie beispielsweise einen Benutzer löschen, möchten Sie möglicherweise die Kommentare, die er in Blog-Posts gepostet hat, beibehalten, sagen jedoch, dass sie von einem anonymen (oder gelöschten) Benutzer gepostet wurden. SQL-Äquivalent: SET NULL
.SET_DEFAULT
: Stellen Sie den Standardwert ein. SQL-Äquivalent: SET DEFAULT
.SET(...)
: Stellen Sie einen bestimmten Wert ein. Dieser ist nicht Teil des SQL-Standards und wird vollständig von Django verwaltet.DO_NOTHING
: Wahrscheinlich eine sehr schlechte Idee, da dies Integritätsprobleme in Ihrer Datenbank verursachen würde (Verweisen auf ein Objekt, das tatsächlich nicht vorhanden ist). SQL-Äquivalent: NO ACTION
.Quelle: Django-Dokumentation
Siehe auch die Dokumentation von PostGreSQL zum Beispiel.
In den meisten Fällen ist CASCADE
das erwartete Verhalten, aber für jeden ForeignKey sollten Sie sich immer fragen, was das erwartete Verhalten in dieser Situation ist. PROTECT
und SET_NULL
sind oft nützlich. Wenn Sie CASCADE
so einstellen, dass dies nicht der Fall ist, können Sie möglicherweise Ihre gesamte Datenbank in Kaskade löschen, indem Sie einfach einen einzelnen Benutzer löschen.
Zusätzlicher Hinweis zur Verdeutlichung der Kaskadenrichtung
Es ist lustig zu bemerken, dass die Richtung der Aktion CASCADE
vielen Menschen nicht klar ist. Eigentlich ist es lustig zu bemerken, dass nur die Aktion CASCADE
nicht klar ist. Ich verstehe, dass das Kaskadenverhalten verwirrend sein könnte, aber Sie müssen denken, dass es ist die gleiche Richtung wie jede andere Aktion. Wenn Sie also das Gefühl haben, dass die CASCADE
Richtung für Sie nicht klar ist, bedeutet dies, dass das on_delete
Verhalten für Sie nicht klar ist.
In Ihrer Datenbank wird ein Fremdschlüssel im Wesentlichen durch ein ganzzahliges Feld dargestellt, dessen Wert der Primärschlüssel des Fremdobjekts ist. Angenommen, Sie haben einen Eintrag comment_A, der einen Fremdschlüssel für einen Eintrag hat article_B. Wenn Sie den Eintrag comment_A löschen, ist alles in Ordnung, article_B wird verwendet, um ohne comment_A zu leben, und stört es nicht, wenn er gelöscht wird. Wenn Sie jedoch article_B löschen, dann comment_A Panics! Es hat nie ohne article_B gelebt und braucht es, es ist Teil seiner Attribute (article=article_B
, aber was ist * article_B ** ???). Hier greift on_delete
ein, um zu bestimmen, wie dieser Integritätsfehler behoben werden soll.
PROTECT
in SQL-Sprache)SET_NULL
)CASCADE
Verhalten).SET_DEFAULT
oder sogar SET(...)
).DO_NOTHING
)Ich hoffe es macht die Kaskadenrichtung klarer. :)
Die on_delete
-Methode teilt Django mit, was mit Modellinstanzen zu tun ist, die von der zu löschenden Modellinstanz abhängen. (z.B. eine ForeignKey
Beziehung). Der on_delete=models.CASCADE
weist Django an, den Löscheffekt zu kaskadieren, d. H. Auch die abhängigen Modelle weiter zu löschen.
Hier ist ein konkreteres Beispiel. Angenommen, Sie haben ein Author
Modell, das ein ForeignKey
in einem Book
Modell ist. Wenn Sie nun eine Instanz des Modells Author
löschen, weiß Django nicht, was mit Instanzen des Modells Book
geschehen soll, die von dieser Instanz von Author
abhängen. Modell. Die on_delete
-Methode teilt Django mit, was in diesem Fall zu tun ist. Wenn Sie on_delete=models.CASCADE
einstellen, wird Django angewiesen, den Löscheffekt zu kaskadieren, d. H. Alle Book
Modellinstanzen zu löschen, die von der Author
Modellinstanz abhängen, die Sie gelöscht haben.
Hinweis: on_delete
wird in Django 2.0 zu einem erforderlichen Argument. In älteren Versionen ist der Standardwert CASCADE
.
Zu Ihrer Information, der on_delete
-Parameter in Modellen ist rückwärts von dem, wie er sich anhört. Sie setzen on_delete
auf einen Fremdschlüssel (FK) eines Modells, um Django mitzuteilen, was zu tun ist, wenn der FK-Eintrag, auf den Sie in Ihrem Datensatz verweisen, gelöscht wird. Die Optionen, die unser Shop am häufigsten verwendet hat, sind PROTECT
, CASCADE
und SET_NULL
. Hier sind die Grundregeln, die ich herausgefunden habe:
PROTECT
, wenn Ihr FK auf eine Nachschlagetabelle zeigt, die sich eigentlich nicht ändern sollte, und mit Sicherheit Ihre Tabelle nicht ändern sollte. Wenn jemand versucht, einen Eintrag in dieser Nachschlagetabelle zu löschen, verhindert PROTECT
, dass er ihn löscht, wenn er mit Datensätzen verknüpft ist. Es verhindert auch, dass Django Ihren Datensatz löscht, nur weil ein Eintrag in einer Nachschlagetabelle gelöscht wurde. Dieser letzte Teil ist kritisch. Wenn jemand das Geschlecht "Weiblich" aus meiner Geschlechtstabelle löschen würde, würde ich BESTIMMT NICHT wollen, dass sofort alle Personen gelöscht werden, die ich in meiner Personentabelle hatte und die dieses Geschlecht hatten.CASCADE
, wenn Ihr FK auf einen "Eltern" -Datensatz zeigt. Also, wenn eine Person viele PersonEthnicity-Einträge haben kann (er/sie kann Indianer, Schwarz und Weiß sein) und diese Person ist gelöscht wird, möchte ich wirklich würde irgendwelche "child" PersonEthnicity-Einträge, die gelöscht werden sollen. Sie sind ohne die Person irrelevant.SET_NULL
, wenn Sie do möchten, dass Personen einen Eintrag in einer Nachschlagetabelle löschen dürfen, Sie aber dennoch Ihren Datensatz beibehalten möchten. Wenn zum Beispiel eine Person eine Highschool haben kann, es mir aber nicht wirklich wichtig ist, ob diese Highschool auf meinem Nachschlagetisch verschwindet, würde ich on_delete=SET_NULL
sagen. Dadurch würde meine Person dort draußen bleiben. es würde einfach nur den High-School-FK meiner Person auf null setzen. Offensichtlich müssen Sie null=True
für diese FK zulassen.Hier ist ein Beispiel für ein Modell, das alle drei Funktionen ausführt:
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'
Wussten Sie, dass, wenn Sie nichton_delete
angeben (oder nicht), das Standardverhalten CASCADE
ist? Das heißt, wenn jemand einen Geschlechtseintrag in Ihrer Geschlechtstabelle gelöscht hat, wurden auch alle Personendatensätze mit diesem Geschlecht gelöscht!
Ich würde sagen: "Wenn Sie Zweifel haben, setzen Sie on_delete=models.PROTECT
." Dann testen Sie Ihre Anwendung. Sie werden schnell herausfinden, welche FKs mit den anderen Werten gekennzeichnet werden sollten, ohne Ihre Daten zu gefährden.
Beachten Sie außerdem, dass on_delete=CASCADE
zu keiner Ihrer Migrationen hinzugefügt wird, wenn Sie dieses Verhalten auswählen. Ich vermute, das liegt daran, dass dies die Standardeinstellung ist, also ist das Setzen von on_delete=CASCADE
dasselbe wie das Setzen von nichts.
Wie bereits erwähnt, löscht CASCADE den Datensatz mit einem Fremdschlüssel und verweist auf ein anderes Objekt, das gelöscht wurde. Zum Beispiel, wenn Sie eine Immobilienwebsite haben und eine Immobilie haben, die auf eine Stadt verweist
_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
_
und jetzt, wenn die Stadt aus der Datenbank gelöscht wird, werden auch alle zugehörigen Immobilien (z. B. Immobilien in dieser Stadt) aus der Datenbank gelöscht
Jetzt möchte ich auch die Vorzüge anderer Optionen erwähnen, wie SET_NULL oder SET_DEFAULT oder sogar DO_NOTHING. Grundsätzlich möchten Sie diese Datensätze aus administrativer Sicht "löschen". Aber Sie wollen nicht wirklich, dass sie verschwinden. Aus vielen Gründen. Jemand hat es möglicherweise versehentlich gelöscht oder es zu Überprüfungs- und Überwachungszwecken. Und einfache Berichterstattung. So kann es eine Möglichkeit sein, die Eigenschaft von einer Stadt "zu trennen". Auch hier kommt es darauf an, wie Ihre Bewerbung geschrieben ist.
Bei einigen Anwendungen ist beispielsweise das Feld "gelöscht" 0 oder 1. Alle Such- und Listenansichten usw., die in Berichten oder von überall, wo der Benutzer über das Front-End darauf zugreifen kann, enthalten keine _deleted == 1
_. Wenn Sie jedoch einen benutzerdefinierten Bericht oder eine benutzerdefinierte Abfrage erstellen, um eine Liste der gelöschten Datensätze abzurufen, und um zu sehen, wann diese zuletzt geändert wurden (ein anderes Feld) und von wem (dh von wem und wann). das ist aus exekutiver sicht sehr vorteilhaft.
Und vergessen Sie nicht, dass Sie versehentliche Löschvorgänge für diese Datensätze so einfach wie _deleted = 0
_ rückgängig machen können.
Mein Punkt ist, wenn es eine Funktionalität gibt, gibt es immer einen Grund dahinter. Nicht immer ein guter Grund. Aber ein Grund. Und oft auch gut.
Hier ist die Antwort auf Ihre Frage: Warum verwenden wir on_delete?
Wenn ein von einem ForeignKey referenziertes Objekt gelöscht wird, emuliert Django standardmäßig das Verhalten der SQL-Einschränkung ON DELETE CASCADE und löscht auch das Objekt, das den ForeignKey enthält. Dieses Verhalten kann durch Angabe des Arguments on_delete außer Kraft gesetzt werden. Wenn Sie beispielsweise einen nicht mehr verwendbaren ForeignKey haben und möchten, dass dieser beim Löschen des referenzierten Objekts auf null gesetzt wird:
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
Die möglichen Werte für on_delete sind in Django.db.models zu finden:
CASCADE: Cascade deletes; der Standard.
PROTECT: Verhindern Sie das Löschen des referenzierten Objekts, indem Sie ProtectedError, eine Unterklasse von Django.db.IntegrityError, auslösen.
SET_NULL: Setzen Sie den ForeignKey auf null; Dies ist nur möglich, wenn null True ist.
SET_DEFAULT: Setzt den ForeignKey auf seinen Standardwert; Für den ForeignKey muss ein Standardwert festgelegt werden.