Wat doet on_delete op Django-modellen?

Ik ben heel bekend met Django, maar ik heb onlangs gemerkt dat er een on_delete=models.CASCADEoptie met de modellen bestaat. Ik heb voor dezelfde documentatie gezocht, maar ik kon niets meer vinden dan:

gewijzigd in Django 1.9:

on_deleteKan nu worden gebruikt als het tweede positionele argument (eerder werd het meestal pas doorgegeven als een trefwoordargument). Het is een vereist argument in Django 2.0.

Een voorbeeld van gebruik is :

from django.db import models
class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...
class Manufacturer(models.Model):
    # ...
    pass

Wat doet on_delete? (Ik denk dat de acties worden gedaan als het model wordt verwijderd .)

Wat doet models.CASCADEDOEN? (Alle tips in documentatie )

Welke andere opties zijn beschikbaar (als mijn gok correct is )?

Waar is de documentatie voor dit verblijf?


Antwoord 1, Autoriteit 100%

Dit is het gedrag om te adopteren wanneer het waarnaar wordt verwezen -object wordt verwijderd. Het is niet specifiek voor Django; Dit is een SQL-standaard. Hoewel Django zijn eigen implementatie heeft bovenop SQL. (1)

Er zijn zeven mogelijke acties om te nemen wanneer een dergelijke gebeurtenis plaatsvindt:

  • CASCADE: wanneer het object waarnaar wordt verwezen wordt verwijderd, verwijder dan ook de objecten die ernaar verwijzen (wanneer u bijvoorbeeld een blogbericht verwijdert, wilt u wellicht ook opmerkingen verwijderen). SQL-equivalent: CASCADE.
  • PROTECT: verbied het verwijderen van het object waarnaar wordt verwezen. Om het te verwijderen, moet u alle objecten die ernaar verwijzen handmatig verwijderen. SQL-equivalent: RESTRICT.
  • RESTRICT: (geïntroduceerd in Django 3.1)Soortgelijk gedrag als PROTECTdat nauwkeuriger overeenkomt met RESTRICTvan SQL. (Zie voorbeeld van django-documentatie)
  • SET_NULL: Stel de verwijzing in op NULL (hiervoor moet het veld nullable zijn). Als u bijvoorbeeld een gebruiker verwijdert, wilt u misschien de opmerkingen die hij op blogposts heeft geplaatst behouden, maar zeggen dat deze zijn geplaatst door een anonieme (of verwijderde) gebruiker. SQL-equivalent: SET NULL.
  • SET_DEFAULT: Stel de standaardwaarde in. SQL-equivalent: SET DEFAULT.
  • SET(...): Stel een bepaalde waarde in. Deze maakt geen deel uit van de SQL-standaard en wordt volledig beheerd door Django.
  • DO_NOTHING: waarschijnlijk een heel slecht idee omdat dit integriteitsproblemen in uw database zou veroorzaken (verwijzend naar een object dat eigenlijk niet bestaat). SQL-equivalent: NO ACTION. (2)

Bron: Django-documentatie

Zie bijvoorbeeld ook de documentatie van PostgreSQL.

In de meeste gevallen is CASCADEhet verwachte gedrag, maar voor elke ForeignKey moet u zich altijd afvragen wat het verwachte gedrag is in deze situatie. PROTECTen SET_NULLzijn vaak handig. Door CASCADEin te stellen waar dit niet zou moeten, kan mogelijk al uw database in cascade worden verwijderd, door simpelweg een enkele gebruiker te verwijderen.


Aanvullende opmerking om de cascaderichting te verduidelijken

Het is grappig om te zien dat de richting van de CASCADE-actie voor veel mensen niet duidelijk is. Het is eigenlijk grappig om te zien dat alleende actie CASCADEniet duidelijk is. Ik begrijp dat het cascadegedrag verwarrend kan zijn, maar je moet denken dat het in dezelfde richting is als elke andere actie. Dus als je denkt dat de richting van CASCADEje niet duidelijk is, betekent dit in feite dat het gedrag van on_deleteje niet duidelijk is.

In uw database wordt een refererende sleutel in feite voorgesteld door een integer veld waarvan de waarde de primaire sleutel is van het refererende object. Stel dat u een item comment_Ahebt, dat een refererende sleutel heeft voor een item article_B. Als u het item comment_Averwijdert, is alles in orde. article_Bleefde zonder comment_Aen maakt zich geen zorgen als het wordt verwijderd. Als u echter article_Bverwijdert, raakt comment_Ain paniek! Het heeft nooit geleefd zonder article_Ben heeft het nodig, en het maakt deel uit van zijn attributen (article=article_B, maar wat is article_B???). Dit is waar on_deletetussenkomt, om te bepalen hoe deze integriteitsfoutkan worden opgelost, hetzij door te zeggen:

  • “Nee! Alsjeblieft! Niet doen! Ik kan niet zonder jou!”(wat wordt gezegd PROTECTof RESTRICTin Django/SQL)
  • “Oké, als ik niet van jou ben, dan ben ik van niemand”(wat wordt gezegd SET_NULL)
  • “Vaarwel wereld, ik kan niet zonder artikel_B”en pleeg zelfmoord (dit is het gedrag van CASCADE).
  • “Het is OK, ik heb een extra minnaar, en ik zal vanaf nu naar article_C verwijzen”(SET_DEFAULT, of zelfs SET(...)).
  • “Ik kan de realiteit niet onder ogen zien, en ik blijf je naam noemen, ook al is dat het enige dat me nog over is!”(DO_NOTHING)

Ik hoop dat het de richting van de cascade duidelijker maakt. 🙂


Voetnoten

(1)Django heeft zijn eigen implementatie bovenop SQL. En, zoals vermeld door @JoeMjr2 in de reacties hieronder, zal Django de SQL-beperkingen niet creëren. Als u wilt dat de beperkingen door uw database worden gewaarborgd (bijvoorbeeld als uw database door een andere toepassing wordt gebruikt of als u af en toe in de databaseconsole blijft hangen), wilt u wellicht de gerelateerde beperkingen zelf handmatig instellen. Er is een open ticketom ondersteuning voor database-niveau toe te voegen aan verwijderingsbeperkingen in Django.

(2)Eigenlijk is er één geval waarin DO_NOTHINGnuttig kan zijn: als je de implementatie van Django wilt overslaan en de beperking zelf op database-niveau wilt implementeren.


Antwoord 2, autoriteit 5%

De methode on_deletewordt gebruikt om Django te vertellen wat hij moet doen met modelinstanties die afhankelijk zijn van de modelinstantie die u verwijdert. (bijvoorbeeld een ForeignKey-relatie). De on_delete=models.CASCADEvertelt Django om het verwijderingseffect te trapsgewijze, d.w.z. door te gaan met het verwijderen van de afhankelijke modellen.

Hier is een meer concreet voorbeeld. Stel dat u een Author-model heeft dat een ForeignKeyis in een Book-model. Als u nu een instantie van het Author-model verwijdert, zou Django niet weten wat hij moet doen met instanties van het Book-model die afhankelijk zijn van die instantie van Author-model. De methode on_deletevertelt Django wat hij in dat geval moet doen. Als u on_delete=models.CASCADEinstelt, instrueert Django het verwijderingseffect trapsgewijs, dwz verwijdert alle Book-modelinstanties die afhankelijk zijn van de Author-modelinstantie die u verwijderd.

Opmerking: on_deletewordt een verplicht argument in Django 2.0. In oudere versies is het standaard CASCADE.

Hier is de volledige officiële documentatie.


Antwoord 3, autoriteit 4%

Ter info, de parameter on_deletein modellen is omgekeerd van hoe het klinkt. Je zet on_deleteop een externe sleutel (FK) op een model om Django te vertellen wat hij moet doen als de FK-invoer waarnaar je verwijst in je record wordt verwijderd. De opties die onze winkel het meest heeft gebruikt, zijn PROTECT, CASCADEen SET_NULL. Dit zijn de basisregels die ik heb bedacht:

  1. Gebruik PROTECTwanneer je FK verwijst naar een opzoektabel die eigenlijk niet zou moeten veranderen en die zekerer niet toe zou moeten leiden dat je tabel verandert. Als iemand een item in die opzoektabel probeert te verwijderen, voorkomt PROTECTdat ze het kunnen verwijderen als het aan records is gekoppeld. Het voorkomt ook dat Django uwrecord verwijdert alleen omdat het een item in een opzoektabel heeft verwijderd. Dit laatste deel is cruciaal. Als iemand het geslacht “Vrouw” uit mijn geslachtstabel zou verwijderen, zou ik ZEKER NIET willen dat dat onmiddellijk alle mensen zou verwijderen die ik in mijn persoonstabel had die dat geslacht hadden.
  2. Gebruik CASCADEwanneer uw FK naar een “ouder” record verwijst. Dus als een persoon veel PersonEthnicity-items kan hebben (hij/zij kan Amerikaans Indiaans, zwart en wit zijn), en die persoon wordtverwijderd, zouecht “child” PersonEthnicity-vermeldingen moeten worden verwijderd. Ze zijn niet relevant zonder de Persoon.
  3. Gebruik SET_NULLwanneer u welwilt dat mensen een item in een opzoektabel mogen verwijderen, maar u toch uw record wilt behouden. Als een persoon bijvoorbeeld een middelbare school kan hebben, maar het maakt mij niet echt uit of die middelbare school op mijn opzoektabel verdwijnt, zou ik zeggen on_delete=SET_NULL. Dit zou mijn Persoonsrecord achterlaten; het zou gewoon de middelbare school FK op mijn Persoon op nul zetten. Uiteraard moet je null=Trueop die FK toestaan.

Hier is een voorbeeld van een model dat alle drie de dingen doet:

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'

Als laatste weetje, wist je dat als je nieton_deleteopgeeft (of niet), het standaardgedrag CASCADE? Dit betekent dat als iemand een geslachtsvermelding in uw geslachtstabel verwijderde, alle persoonsrecords met dat geslacht ook werden verwijderd!

Ik zou zeggen: “In geval van twijfel, stel on_delete=models.PROTECTin.” Ga dan je aanvraag testen. U zult snel ontdekken welke FK’s de andere waarden moeten worden gelabeld zonder uw gegevens in gevaar te brengen.

Het is ook vermeldenswaard dat on_delete=CASCADEeigenlijk niet wordt toegevoegd aan uw migraties, als dat het gedrag is dat u selecteert. Ik denk dat dit komt omdat het de standaard is, dus on_delete=CASCADEplaatsen is hetzelfde als niets plaatsen.


Antwoord 4, autoriteit 2%

Zoals eerder vermeld, verwijdert CASCADE het record met een externe sleutel en verwijst het naar een ander object dat is verwijderd. Dus als u bijvoorbeeld een onroerendgoedwebsite heeft en een onroerend goed heeft dat verwijst naar een stad

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

en nu wanneer de stad uit de database wordt verwijderd, worden alle bijbehorende eigendommen (bijv. onroerend goed in die stad) ook uit de database verwijderd

Nu wil ik ook de verdienste van andere opties noemen, zoals SET_NULL of SET_DEFAULT of zelfs DO_NOTHING. Kortom, vanuit het oogpunt van de administratie, wilt u die records “verwijderen”. Maar je wilt niet dat ze verdwijnen. Om vele redenen. Iemand heeft het misschien per ongeluk verwijderd, of voor controle en monitoring. En duidelijke berichtgeving. Het kan dus een manier zijn om het onroerend goed te “ontkoppelen” van een stad. Nogmaals, het hangt af van hoe uw aanvraag is geschreven.

Sommige toepassingen hebben bijvoorbeeld een veld “verwijderd” dat 0 of 1 is. En al hun zoekopdrachten en lijstweergaven enz., alles wat in rapporten kan verschijnen of waar de gebruiker er vanaf de voorkant toegang toe heeft, sluit alles uit is deleted == 1. Als u echter een aangepast rapport of een aangepaste query maakt om een lijst met records op te halen die zijn verwijderd en nog meer om te zien wanneer het voor het laatst is gewijzigd (een ander veld) en door wie (dwz wie het heeft verwijderd en wanneer). dat is erg voordelig vanuit uitvoerend oogpunt.

En vergeet niet dat u onbedoelde verwijderingen voor die records zo eenvoudig als deleted = 0ongedaan kunt maken.

Mijn punt is dat als er een functionaliteit is, er altijd een reden achter zit. Niet altijd een goede reden. Maar een reden. En vaak ook nog een goede.


Antwoord 5

Hier is het antwoord op uw vraag: waarom gebruiken we on_delete?

Wanneer een object waarnaar wordt verwezen door een ForeignKey wordt verwijderd, emuleert Django standaard het gedrag van de SQL-beperking ON DELETE CASCADE en verwijdert ook het object dat de ForeignKey bevat. Dit gedrag kan worden overschreven door het argument on_delete op te geven. Als u bijvoorbeeld een ForeignKey met een nulwaarde hebt en u wilt dat deze op nul wordt gezet wanneer het object waarnaar wordt verwezen, wordt verwijderd:

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

De mogelijke waarden voor on_delete zijn te vinden in django.db.models:

CASCADE:Cascade verwijdert; de standaard.

PROTECT:Voorkom verwijdering van het object waarnaar wordt verwezen door ProtectedError, een subklasse van django.db.IntegrityError, te verhogen.

SET_NULL:stel de ForeignKey null in; dit is alleen mogelijk als null waar is.

SET_DEFAULT:Stel de ForeignKey in op de standaardwaarde; er moet een standaard voor de ForeignKey worden ingesteld.


Antwoord 6

Het gebruik van CASCADEbetekent dat je Django daadwerkelijk vertelt het record waarnaar wordt verwezen te verwijderen.
In het onderstaande voorbeeld van de poll-app: Wanneer een ‘Vraag’ wordt verwijderd, worden ook de keuzes die deze vraag heeft verwijderd.

bijv. Vraag: Hoe heeft u over ons gehoord?
(Keuzes: 1. Vrienden 2. TV-advertentie 3. Zoekmachine 4. E-mailpromotie)

Als je deze vraag verwijdert, worden ook al deze vier keuzes uit de tabel verwijderd.
Let op in welke richting het stroomt.
U hoeft on_delete=models.CASCADE in Vraagmodel niet in te voeren, plaats het in de Keuze.

from django.db import models
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.dateTimeField('date_published')
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_legth=200)
    votes = models.IntegerField(default=0)

Antwoord 7

Stel dat je twee modellen hebt, een met de naam Persoonen een ander met de naam Bedrijven.

Per definitie kan één persoon meer dan één bedrijf oprichten.

Aangezien een bedrijf één en slechts één persoon kan hebben, willen we dat wanneer een persoon wordt verwijderd, alle bedrijven die aan die persoon zijn gekoppeld, ook worden verwijderd.

Dus we beginnen met het maken van een persoonsmodel, zoals dit

class Person(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=20)
    def __str__(self):
        return self.id+self.name

Het bedrijfsmodel kan er dan zo uitzien

class Companies(models.Model):
    title = models.CharField(max_length=20)
    description=models.CharField(max_length=10)
    person= models.ForeignKey(Person,related_name='persons',on_delete=models.CASCADE)

Let op het gebruik van on_delete=models.CASCADEin het model Bedrijven. Dat is om alle bedrijven te verwijderen wanneer de persoon die het bezit (bijvoorbeeld klasse Persoon) wordt verwijderd.


Antwoord 8

Heroriënteer je mentale model van de functionaliteit van “CASCADE” door te denken aan het toevoegen van een FK aan een reeds bestaande cascade (d.w.z. een waterval). De bron van deze waterval is een primaire sleutel (PK). Verwijderingen stromen naar beneden.

Dus als u een FK’s On_Delete definieert als “Cascade”, voegt u deze FK’s record aan een cascade van Wissen afkomstig van de PK. Het record van de FK kan deelnemen aan deze cascade of niet (“set_null”). In feite kan een record met een FK zelfs de stroom van de verwijderingen voorkomen! Bouw een dam met “Protect”.


Antwoord 9

Cascade verwijdert ook het overeenkomstige veld dat ermee is verbonden.


Antwoord 10

Verwijdert alle kind velden in de database, dan gebruiken we on_delete zoals SO:

class user(models.Model):
 commodities = models.ForeignKey(commodity, on_delete=models.CASCADE)

Other episodes