que fait on delete sur les modèles Django?

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

Changé dans Django 1.9:

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

Un exemple de cas d'utilisation est

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? (deviner l'action à faire si le modèle est supprimé)

Qu'est-ce que les modèles.CASCADE de faire? ( tous les indices dans la documentation)

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

Où se trouve la documentation pour cela?

134
demandé sur Antoine Pinsard 2016-07-15 08:26:57

5 réponses

C'est le comportement à adopter lorsque l'objet référencé est supprimé. Ce n'est pas spécifique à django, c'est un standard SQL.

Il y a 6 actions possibles à prendre quand un tel événement se produit:

  • CASCADE: lorsque l'objet référencé est supprimé, supprimez également les objets qui y sont référencés (lorsque vous supprimez un article de blog par exemple, vous pouvez également supprimer des commentaires). Équivalent SQL: CASCADE.
  • PROTECT: Interdire la suppression de la objet référencé. Pour le supprimer, vous devrez supprimer tous les objets qui le référencent manuellement. Équivalent SQL: RESTRICT.
  • SET_NULL: définit la référence à NULL (nécessite que le champ soit nullable). Par exemple, lorsque vous supprimez un Utilisateur, vous voudrez peut-être garder les commentaires qu'il a posté sur le blogue, mais dire qu'il a été posté par un anonyme (ou supprimé) de l'utilisateur. Équivalent SQL: SET NULL.
  • SET_DEFAULT: définit la valeur par défaut. Équivalent SQL: SET DEFAULT.
  • SET(...): définit une valeur donnée. Celui-ci est ne fait pas partie du standard SQL et est entièrement géré 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 pas réellement). Équivalent SQL: NO ACTION.

Source: documentation de Django

Voir aussi la documentation de PostGreSQL, par exemple.

Dans la plupart des cas, CASCADE est le comportement attendu, mais pour chaque ForeignKey, vous devriez toujours demander vous-même quel est le comportement attendu dans cette situation. PROTECT et SET_NULL sont souvent utiles. Définir CASCADE là où il ne devrait pas, peut potentiellement supprimer toute votre base de données en cascade, en supprimant simplement un seul utilisateur.

251
répondu Antoine Pinsard 2018-07-19 09:15:58

La méthode on_delete est utilisée pour indiquer à Django ce qu'il faut faire avec les instances de modèle qui dépendent de l'instance de modèle que vous supprimez. (par exemple une relation ForeignKey). Le on_delete=models.CASCADE indique à Django de mettre en cascade l'effet de suppression, c'est-à-dire de continuer à supprimer les modèles dépendants.

Voici un exemple plus concret. Supposons que vous ayez un modèle Author qui est un ForeignKey dans un modèle Book. Maintenant, si vous supprimez une instance du modèle Author, Django ne saurait pas quoi faire avec les instances du modèle Book qui dépend de cette instance du modèle Author. La méthode on_delete indique à Django ce qu'il faut faire dans ce cas. Le paramètre on_delete=models.CASCADE indiquera à Django de mettre en cascade l'effet de suppression, c'est-à-dire de supprimer toutes les instances de modèle Book qui dépendent de l'instance de modèle Author que vous avez supprimée.

Remarque: on_delete deviendra un argument obligatoire dans Django 2.0. Dans les anciennes versions, il est par défaut CASCADE.

Voici toute la documentation officielle.

27
répondu Himank Yadav 2017-04-14 21:04:24

POUR INFO, le paramètre on_delete dans les modèles est en arrière de ce à quoi il ressemble. Vous mettez "on_delete" sur une clé étrangère (FK) sur un modèle pour dire à django quoi 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 et SET_NULL. Voici les règles de base que j'ai trouvées:

  1. Utilisez PROTECT lorsque votre FK pointe vers une table de recherche qui ne devrait vraiment pas changer et que devrait certainement {[6] } pas causer votre table à changer. Si quelqu'un essaie de supprimer une entrée sur cette table de recherche, PROTECT l'empêche de la supprimer si elle est liée à des enregistrements. Il empêche également django de supprimer Votre enregistrement simplement parce qu'il a supprimé une entrée sur une table de recherche. Cette dernière partie est critique. Si quelqu'un devait supprimer le genre "Femelle" de ma table de genre, Je ne voudrais certainement pas que cela supprime instantanément toutes les personnes que j'avais dans ma table de personne qui avaient cela sexe.
  2. Utilisez CASCADE lorsque votre FK pointe vers un enregistrement "parent". Donc, si une personne peut avoir beaucoup d'entrées de PersonEthnicity (il / elle peut être Indien Américain, noir et blanc), et que cette personne est supprimée, je voudrais vraiment que toutes les entrées de PersonEthnicity "enfants" soient supprimées. Ils ne sont pas pertinents sans la personne.
  3. Utilisez SET_NULL lorsque vous voulez que les personnes soient autorisées à supprimer une entrée sur une table de recherche, mais que vous voulez toujours conserver votre dossier. Par exemple, si une personne peut avoir un lycée, mais cela n'a pas vraiment d'importance pour moi si ce lycée disparaît sur ma table de consultation, je dirais "on_delete=SET_NULL."Cela laisserait mon enregistrement de personne là-bas; cela mettrait simplement le FK du lycée sur ma personne à null . Évidemment, vous devrez autoriser null = True sur ce FK.

Voici un exemple de modèle qui fait les 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'

Comme une dernière friandise, saviez-vous que si vous n'est pas spécifiez on_delete (ou n'a pas), le comportement par défaut est CASCADE? Cela signifie que si quelqu'un a supprimé une entrée de genre sur votre table de genre, tous les enregistrements de personne avec ce genre ont également été supprimés!

Je dirais: "en cas de doute, définissez on_delete=models.PROTÉGER."Ensuite, allez tester votre application. Vous comprendrez rapidement quels FK doivent être étiquetés les autres valeurs sans mettre en danger vos données.

En outre, il est à noter que on_delete = CASCADE n'est en fait pas ajouté à l'un des vos migrations, si c'est le comportement que vous sélectionnez. Je suppose que c'est parce que c'est la valeur par défaut, donc mettre on_delete=CASCADE est la même chose que de ne rien mettre.

16
répondu HelenM 2017-12-21 19:47:09

Voici la réponse à votre question qui dit: pourquoi nous utilisons on_delete?

Lorsqu'un objet référencé par une ForeignKey est supprimé, Django émule par défaut le comportement de la contrainte SQL sur DELETE CASCADE et supprime également l'objet contenant la ForeignKey. Ce comportement peut être remplacé en spécifiant l'argument on_delete. Par exemple, si vous avez un ForeignKey nullable et que vous voulez qu'il soit défini null lorsque l'objet référencé est supprimé:

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

Le les valeurs possibles pour on_delete se trouvent dans django.DB.modèles:

CASCADE: Cascade supprime; la valeur par défaut.

PROTECT: empêche la suppression de l'objet référencé en déclenchant ProtectedError, une sous-classe de django.DB.IntegrityError.

SET_NULL: définit la valeur NULL ForeignKey; ceci n'est possible que si null est vrai.

SET_DEFAULT: définit la ForeignKey à sa valeur par défaut; une valeur par défaut pour la ForeignKey doit être définie.

1
répondu Sonia Rani 2018-08-14 07:31:26

Comme mentionné précédemment, CASCADE supprimera l'enregistrement qui a une clé étrangère et référencera un autre objet qui a été supprimé. Ainsi, par exemple, si vous avez un site immobilier et 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. immobilier situé dans la ville) seront également supprimés de la base de données

Maintenant, je veux aussi 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 la surveillance. Et la plaine de la production de 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 demande est écrite.

Par exemple, certaines applications ont un champ "supprimé", qui est 0 ou 1. Et toutes leurs recherches et liste vues etc, Tout ce qui peut apparaître dans les rapports ou n'importe où l'utilisateur peut y accéder à partir du frontal, exclure tout ce qui est deleted == 1. Cependant, si vous créez un rapport personnalisé ou une requête personnalisée pour tirer vers le bas une liste d'enregistrements qui ont été supprimés et plus encore pour voir quand il a été modifié pour la dernière fois (un autre champ) et par qui (c'est-à-dire qui l'a supprimé et quand)..c'est très avantageux du point de vue de l'exécutif.

Et n'oubliez pas que vous pouvez annuler les suppressions accidentelles aussi simples que deleted = 0 pour ces enregistrements.

Mon point est, s'il y a une fonctionnalité, il y a toujours une raison derrière cela. Pas toujours une bonne raison. Mais une raison. Et souvent une bonne trop.

0
répondu George Mogilevsky 2018-07-19 15:37:36