639 votes

Que fait on_delete sur les modèles Django ?

Je suis assez familier avec Django, mais j'ai récemment remarqué qu'il existe une on_delete=models.CASCADE option avec les modèles. J'ai cherché la documentation pour la même chose, mais je n'ai rien trouvé de plus :

Modifié dans Django 1.9 :

on_delete peut maintenant être utilisé comme deuxième argument positionnel (auparavant, il n'était généralement passé que comme argument mot-clé). Ce sera un argument obligatoire dans Django 2.0.

Voici un exemple d'utilisation :

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

Que fait on_delete ? ( Je suppose que les actions à effectuer si le modèle est supprimé .)

Qu'est-ce que models.CASCADE faire ? ( des conseils dans la documentation )

Quelles autres options sont disponibles ( si ma supposition est correcte ) ?

Où se trouve la documentation à ce sujet ?

0 votes

Vous trouverez également une réponse à une question similaire à l'adresse suivante stackoverflow.com/questions/47914325/

1 votes

Le texte de cette question similaire est maintenant listé, ci-dessous, sur cette réponse. Il commence par "FYI, le paramètre on_delete dans les modèles est inversé par rapport à ce qu'il semble être". Il fournit beaucoup plus de détails que les réponses originales.

0 votes

Vous pouvez trouver une bonne réponse dans le lien ci-dessous. medium.com/@inem.patrick/

1450voto

Antoine Pinsard Points 696

C'est le comportement à adopter lorsque le référencé est supprimé. Ce n'est pas spécifique à Django ; il s'agit d'une norme SQL. Bien que Django ait sa propre implémentation au-dessus de SQL. (1)

Il existe sept actions possibles à entreprendre lorsqu'un tel événement se produit :

  • CASCADE : Lorsque l'objet référencé est supprimé, il faut également supprimer les objets qui y font référence (lorsque vous supprimez un article de blog par exemple, vous pourriez vouloir supprimer également les commentaires). Équivalent SQL : CASCADE .
  • PROTECT : Interdire la suppression de l'objet référencé. Pour le supprimer, vous devrez supprimer manuellement tous les objets qui le référencent. Équivalent SQL : RESTRICT .
  • RESTRICT : (introduit dans Django 3.1) Comportement similaire à celui de PROTECT qui correspond à celle de SQL RESTRICT de façon plus précise. (Voir exemple de documentation django )
  • SET_NULL : Mettre la référence à NULL (nécessite que le champ soit nullable). Par exemple, lorsque vous supprimez un utilisateur, vous pouvez vouloir conserver les commentaires qu'il a postés sur des articles de blog, mais dire qu'ils ont été postés par un utilisateur anonyme (ou supprimé). Équivalent SQL : SET NULL .
  • SET_DEFAULT : Définir la valeur par défaut. Équivalent SQL : SET DEFAULT .
  • SET(...) : Définir une valeur donnée. Celle-ci ne fait pas partie de la norme SQL et est entièrement gérée par Django.
  • DO_NOTHING : Probablement une très mauvaise idée car cela créerait des problèmes d'intégrité dans votre base de données (référencement d'un objet qui n'existe en réalité pas). Équivalent SQL : NO ACTION . (2)

Fuente: Documentation sur Django

Voir aussi la documentation de PostgreSQL par exemple.

Dans la plupart des cas, CASCADE est le comportement attendu, mais pour chaque clé étrangère, vous devez toujours vous demander quel est le comportement attendu dans cette situation. PROTECT y SET_NULL sont souvent utiles. Réglage du site CASCADE où il ne devrait pas, peut potentiellement supprimer toute votre base de données en cascade, en supprimant simplement un seul utilisateur.


Note supplémentaire pour clarifier la direction de la cascade

Il est amusant de remarquer que la direction de la CASCADE L'action n'est pas claire pour beaucoup de gens. En fait, c'est amusant de remarquer que uniquement le site CASCADE L'action n'est pas claire. Je comprends que le comportement en cascade puisse être déroutant, cependant vous devez penser que c'est le même sens que toute autre action . Ainsi, si vous estimez que CASCADE n'est pas claire pour vous, cela signifie en fait que on_delete comportement n'est pas clair pour vous.

Dans votre base de données, une clé étrangère est essentiellement représentée par un champ entier dont la valeur est la clé primaire de l'objet étranger. Disons que vous avez une entrée commentaire_A qui a une clé étrangère vers une entrée article_B . Si vous supprimez l'entrée commentaire_A tout va bien. article_B l'habitude de vivre sans commentaire_A et ne vous inquiétez pas si elle est supprimée. Cependant, si vous supprimez article_B alors commentaire_A panique ! Il n'a jamais vécu sans article_B et en a besoin, et cela fait partie de ses attributs ( article=article_B mais ce qui est article_B ? ??). C'est là que on_delete intervient, pour déterminer comment résoudre cette erreur d'intégrité soit en disant :

  • "Non ! S'il vous plaît ! Ne faites pas ça ! Je ne peux pas vivre sans toi !" (qui est dit PROTECT o RESTRICT en Django/SQL)
  • "D'accord, si je ne suis pas à toi, alors je ne suis à personne". (qui est dit SET_NULL )
  • "Au revoir le monde, je ne peux pas vivre sans article_B". et se suicider (c'est le CASCADE comportement).
  • "C'est bon, j'ai un amant de rechange, et je vais référencer l'article_C à partir de maintenant". ( SET_DEFAULT ou encore SET(...) ).
  • "Je ne peux pas faire face à la réalité, et je continuerai à appeler ton nom même si c'est la seule chose qui me reste !" ( DO_NOTHING )

J'espère que cela rend la direction de la cascade plus claire :)


Notes de bas de page

(1) Django a sa propre implémentation au-dessus de SQL. Et, comme mentionné par @JoeMjr2 dans les commentaires ci-dessous Django ne créera pas les contraintes SQL. Si vous souhaitez que les contraintes soient assurées par votre base de données (par exemple, si votre base de données est utilisée par une autre application, ou si vous traînez dans la console de la base de données de temps en temps), vous pouvez définir vous-même les contraintes correspondantes manuellement. Il existe un ticket ouvert pour ajouter la prise en charge des contraintes de suppression au niveau de la base de données dans Django.

(2) En fait, il y a un cas où DO_NOTHING peut être utile : Si vous voulez sauter l'implémentation de Django et implémenter vous-même la contrainte au niveau de la base de données.

31 votes

C'est une question idiote, mais les cascades doivent toujours être unidirectionnelles, non ? C'est-à-dire que si Comment a une clé étrangère vers BlogPost alors la suppression du BlogPost devrait supprimer le Commentaire, mais la suppression du Commentaire ne devrait pas supprimer le BlogPost, quel que soit le SGRD ?

29 votes

@AnthonyManningFranklin Bien sûr, la suppression n'est déclenchée que lorsqu'une référence est "cassée". Ce qui n'est pas le cas lorsque vous supprimez un commentaire, car vous supprimez la référence en même temps.

8 votes

La question n'est pas idiote, j'ai aussi besoin de cette explication. Donc ici nous supposons que la relation est uni-latérale, le propriétaire de la relation est Comment qui a le champ FK dans sa table, alors que BlogPost "possède" Comment si l'on parle du modèle de la vie réelle. Bien.

69voto

Himank Yadav Points 463

El on_delete est utilisée pour indiquer à Django ce qu'il doit faire avec les instances de modèle qui dépendent de l'instance de modèle que vous supprimez. (par exemple, une ForeignKey ). Le site on_delete=models.CASCADE indique à Django de cascader l'effet de suppression, c'est-à-dire de continuer à supprimer les modèles dépendants également.

Voici un exemple plus concret. Supposons que vous ayez un Author qui est un ForeignKey dans un Book modèle. Maintenant, si vous supprimez une instance du Author Django ne saurait pas quoi faire avec les instances du modèle Book qui dépendent de cette instance de Author modèle. Le site on_delete indique à Django ce qu'il doit faire dans ce cas. Configuration de on_delete=models.CASCADE demandera à Django de procéder à la suppression en cascade, c'est-à-dire de supprimer tous les fichiers Book les instances du modèle qui dépendent de la Author instance du modèle que vous avez supprimé.

Nota: on_delete deviendra un argument obligatoire dans Django 2.0. Dans les versions antérieures, la valeur par défaut est CASCADE .

Voici l'intégralité de la documentation officielle.

56voto

HelenM Points 316

Pour info, le on_delete Le paramètre dans les modèles est à l'envers de ce qu'il semble être. Vous mettez on_delete sur une clé étrangère (FK) sur un modèle pour indiquer à Django ce qu'il faut faire si l'entrée FK que vous pointez sur votre enregistrement est supprimée. Les options que notre boutique a le plus utilisées sont PROTECT , CASCADE y SET_NULL . Voici les règles de base que j'ai établies :

  1. Utilisez PROTECT quand votre FK pointe vers une table de consultation qui ne devrait pas changer et qui certainement ne devrait pas entraîner de modification de votre tableau. Si quelqu'un essaie de supprimer une entrée dans cette table de consultation, PROTECT les empêche de le supprimer s'il est lié à des enregistrements. Cela empêche également Django de supprimer su juste parce qu'il a supprimé une entrée dans une table de consultation. Cette dernière partie est essentielle. Si quelqu'un supprimait le sexe "Femme" de ma table Sexe, je ne voudrais CERTAINEMENT PAS que cela supprime instantanément toutes les personnes de ce sexe qui figurent dans ma table Personne.
  2. Utilisez CASCADE lorsque votre FK pointe vers un enregistrement "parent". Ainsi, si une personne peut avoir plusieurs entrées PersonEthnicity (elle peut être amérindienne, noire et blanche), et que cette personne es supprimé, j'ai vraiment serait Je veux que toutes les entrées PersonEthnicity "enfants" soient supprimées. Elles ne sont pas pertinentes sans la Personne.
  3. Utilisez SET_NULL quand vous faire vous voulez que les gens soient autorisés à supprimer une entrée dans une table de consultation, mais vous voulez quand même préserver votre enregistrement. Par exemple, si une personne peut avoir un lycée, mais qu'il m'importe peu que ce lycée disparaisse de ma table de consultation, je dirais ceci on_delete=SET_NULL . Cela laisserait l'enregistrement de ma Personne en place ; cela mettrait simplement le FK du lycée sur ma Personne à zéro. Évidemment, vous devrez autoriser null=True sur ce FK.

Voici un exemple de modèle qui fait ces trois choses :

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'

Pour finir, saviez-vous que si vous Ne le fais pas. spécifier on_delete (ou ne l'a pas fait), le comportement par défaut est le suivant CASCADE ? Cela signifie que si quelqu'un supprime une entrée de genre dans votre table Gender, tous les enregistrements Person avec ce genre sont également supprimés !

Je dirais : "En cas de doute, mettez on_delete=models.PROTECT ." Ensuite, allez tester votre application. Vous découvrirez rapidement quels FKs doivent être étiquetés des autres valeurs sans mettre en danger vos données.

Il convient également de noter que on_delete=CASCADE n'est en fait ajouté à aucune de vos migrations, si c'est le comportement que vous choisissez. Je suppose que c'est parce que c'est le comportement par défaut, donc mettre on_delete=CASCADE c'est la même chose que de ne rien mettre.

24voto

Comme mentionné précédemment, CASCADE supprime l'enregistrement qui possède une clé étrangère et qui fait référence à un autre objet qui a été supprimé. Ainsi, par exemple, si vous avez un site Web de biens immobiliers et que vous avez une propriété qui fait référence à une ville

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

et maintenant, lorsque la ville est supprimée de la base de données, toutes les propriétés associées (par exemple, les biens immobiliers situés dans cette ville) seront également supprimées de la base de données.

Maintenant, je veux également mentionner le mérite d'autres options, telles que SET_NULL ou SET_DEFAULT ou même DO_NOTHING. Fondamentalement, du point de vue de l'administration, vous voulez "supprimer" ces enregistrements. Mais vous ne voulez pas vraiment qu'ils disparaissent. Pour de nombreuses raisons. Quelqu'un pourrait l'avoir supprimé accidentellement, ou pour l'audit et le suivi. Et tout simplement pour faire des rapports. Cela peut donc être un moyen de "déconnecter" la propriété d'une ville. Encore une fois, cela dépendra de la façon dont votre application est écrite.

Par exemple, certaines applications ont un champ "supprimé" qui vaut 0 ou 1. Et toutes leurs recherches et vues de liste, etc., tout ce qui peut apparaître dans les rapports ou partout où l'utilisateur peut y accéder à partir du front-end, excluent tout ce qui est "supprimé". deleted == 1 . Cependant, si vous créez un rapport personnalisé ou une requête personnalisée pour obtenir une liste des enregistrements qui ont été supprimés et, plus encore, pour voir quand ils ont été modifiés pour la dernière fois (un autre champ) et par qui (c'est-à-dire qui les a supprimés et quand), cela est très avantageux du point de vue de la direction.

Et n'oubliez pas que vous pouvez revenir sur des suppressions accidentelles aussi simplement que deleted = 0 pour ces dossiers.

Ce que je veux dire, c'est que s'il y a une fonctionnalité, il y a toujours une raison derrière. Pas toujours une bonne raison. Mais une raison. Et souvent une bonne raison aussi.

7 votes

Cela a été utile car cela a permis de clarifier dans quelle direction le CASCADE se produit. La réponse acceptée n'est pas claire si vous n'êtes pas familier avec les cascades SQL.

0 votes

Merci :) j'apprécie beaucoup !

2 votes

Je vote cette réponse car elle répond à mon doute sur la direction du modèle de relation.

8voto

Sonia Rani Points 160

Voici la réponse à votre question : pourquoi utiliser on_delete ?

Lorsqu'un objet référencé par une clé étrangère est supprimé, Django émule par défaut le comportement de la contrainte SQL ON DELETE CASCADE et supprime également l'objet contenant la clé étrangère. Ce comportement peut être modifié en spécifiant l'argument on_delete. Par exemple, si vous avez une ForeignKey nullable et que vous voulez qu'elle soit mise à zéro lorsque l'objet référencé est supprimé :

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

Les valeurs possibles pour on_delete se trouvent dans django.db.models :

CASCADE : Suppression en cascade ; la valeur par défaut.

PROTÉGER : Empêche la suppression de l'objet référencé en déclenchant ProtectedError, une sous-classe de django.db.IntegrityError.

SET_NULL : Définir le ForeignKey null ; ceci n'est possible que si null est True.

SET_DEFAULT : Définir le ForeignKey à sa valeur par défaut ; une valeur par défaut pour le ForeignKey doit être définie.

0 votes

Des mots simples rendent les choses plus claires pour moi, car je ne suis pas mature avec sql et django aussi. Merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X