it-swarm.com.de

Was macht on_delete bei Django Modellen?

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.

ein Anwendungsbeispiel ist

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?

238
Marty

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.

  • "Nein! Bitte! Nicht! Ich kann nicht ohne dich leben!" (das heißt PROTECT in SQL-Sprache)
  • "Okay, wenn ich nicht dein bin, dann bin ich niemandes" (das heißt SET_NULL)
  • "Auf Wiedersehen Welt, ich kann nicht ohne Artikel_B leben" und Selbstmord begehen (dies ist das CASCADE Verhalten).
  • "Es ist in Ordnung, ich habe Ersatzliebhaber, ich werde ab sofort auf Artikel_C verweisen" (SET_DEFAULT oder sogar SET(...)).
  • "Ich kann mich der Realität nicht stellen, ich rufe weiterhin deinen Namen, auch wenn das das einzige ist, was mir noch bleibt!" (DO_NOTHING)

Ich hoffe es macht die Kaskadenrichtung klarer. :)

467
Antoine Pinsard

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.

Hier ist die gesamte offizielle Dokumentation.

37
Himank Yadav

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:

  1. Verwenden Sie 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.
  2. Verwenden Sie 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.
  3. Verwenden Sie 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.

29
HelenM

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.

7

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.

4
Sonia Rani