on_delete modelos delete python django django-models

python - ¿Qué hace on_delete en los modelos Django?



on delete set null django (7)

Estoy bastante familiarizado con Django, pero recientemente noté que existe una opción on_delete=models.CASCADE con los modelos, he buscado la documentación para el mismo pero no pude encontrar nada más que:

Cambiado en Django 1.9:

on_delete ahora se puede usar como el segundo argumento posicional (anteriormente, por lo general, solo se pasaba como argumento de palabra clave). Será un argumento obligatorio en Django 2.0.

un ejemplo de caso de uso es

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

¿Qué hace on_delete? ( Supongo que las acciones a realizar si se elimina el modelo )

¿Qué hace models.CASCADE ? ( cualquier pista en la documentación )

¿Qué otras opciones están disponibles ( si mi suposición es correcta )?

¿Dónde reside la documentación para esto?


Como se mencionó anteriormente, CASCADE eliminará el registro que tenga una clave foránea y haga referencia a otro objeto que se eliminó. Entonces, por ejemplo, si tiene un sitio web de bienes raíces y tiene una Propiedad que hace referencia a una Ciudad

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

y ahora, cuando la Ciudad se elimina de la base de datos, todas las Propiedades asociadas (por ejemplo, bienes inmuebles ubicados en esa ciudad) también se eliminarán de la base de datos

Ahora también quiero mencionar el mérito de otras opciones, como SET_NULL o SET_DEFAULT o incluso DO_NOTHING. Básicamente, desde la perspectiva de la administración, desea "eliminar" esos registros. Pero realmente no quieres que desaparezcan. Por muchas razones. Alguien podría haberlo eliminado accidentalmente, o para auditar y monitorear. Y simple presentación de informes. Por lo tanto, puede ser una forma de "desconectar" la propiedad de una ciudad. Nuevamente, dependerá de cómo se escriba su solicitud.

Por ejemplo, algunas aplicaciones tienen un campo "eliminado" que es 0 o 1. Y todas sus búsquedas y vistas de lista, etc., cualquier cosa que pueda aparecer en los informes o en cualquier lugar donde el usuario pueda acceder desde el extremo frontal, excluye cualquier cosa que se deleted == 1 . Sin embargo, si crea un informe personalizado o una consulta personalizada para desplegar una lista de registros que se eliminaron y aún más para ver cuándo se modificó por última vez (otro campo) y quién (es decir, quién lo eliminó y cuándo). eso es muy ventajoso desde el punto de vista ejecutivo.

Y no olvide que puede revertir eliminaciones accidentales tan simples como deleted = 0 para esos registros.

Mi punto es, si hay una funcionalidad, siempre hay una razón detrás de esto. No siempre es una buena razón. Pero una razón. Y a menudo uno bueno también.


El método on_delete se usa para decirle a Django qué hacer con las instancias de modelo que dependen de la instancia de modelo que elimine. (por ejemplo, una relación ForeignKey ). on_delete=models.CASCADE le dice a Django que on_delete=models.CASCADE en cascada el efecto de eliminación, es decir, que continúe eliminando también los modelos dependientes.

Aquí hay un ejemplo más concreto. Suponga que tiene un modelo de Author que es una ForeignKey en un modelo de Book . Ahora, si elimina una instancia del modelo de Author , Django no sabría qué hacer con las instancias del modelo de Book que dependen de esa instancia del modelo de Author . El método on_delete le dice a Django qué hacer en ese caso. La configuración de on_delete=models.CASCADE le on_delete=models.CASCADE a Django que ponga en cascada el efecto de eliminación, es decir, elimine todas las instancias de modelo de Book que dependen de la instancia de modelo de Author que eliminó.

Nota: on_delete se convertirá en un argumento obligatorio en Django 2.0. En versiones anteriores, el valor predeterminado es CASCADE .

Aquí está toda la documentación oficial.


Este es el comportamiento a adoptar cuando se elimina el objeto referenciado . No es específico de django, este es un estándar SQL.

Hay 6 posibles acciones a tomar cuando se produce dicho evento:

  • CASCADE : cuando se elimina el objeto al que se hace referencia, también elimine los objetos que tienen referencias a él (cuando elimina una publicación de blog, por ejemplo, es posible que también desee eliminar los comentarios). Equivalente de SQL: CASCADE .
  • PROTECT : Prohibir la eliminación del objeto referenciado. Para eliminarlo, deberá eliminar todos los objetos que lo referencian manualmente. Equivalente de SQL: RESTRICT .
  • SET_NULL : establece la referencia en NULL (requiere que el campo sea anulable). Por ejemplo, cuando elimina un usuario, es posible que desee conservar los comentarios que publicó en las publicaciones de blog, pero digamos que fue publicado por un usuario anónimo (o eliminado). Equivalente de SQL: SET NULL .
  • SET_DEFAULT : establece el valor predeterminado. Equivalente de SQL: SET DEFAULT .
  • SET(...) : establece un valor dado. Este no es parte del estándar SQL y es manejado completamente por Django.
  • DO_NOTHING : Probablemente sea una muy mala idea, ya que esto crearía problemas de integridad en su base de datos (haciendo referencia a un objeto que en realidad no existe). Equivalente de SQL: NO ACTION .

Fuente: documentación de Django

Consulte también la documentación de PostGreSQL por ejemplo.

En la mayoría de los casos, CASCADE es el comportamiento esperado, pero para cada ForeignKey, siempre debe preguntarse cuál es el comportamiento esperado en esta situación. PROTECT y SET_NULL son a menudo útiles. Configurar CASCADE donde no debería, puede eliminar potencialmente toda su base de datos en cascada, simplemente eliminando un solo usuario.


Para su información, el parámetro on_delete en modelos está al revés de lo que parece. on_delete en una clave externa (FK) en un modelo para decirle a django qué hacer si se elimina la entrada FK a la que estás apuntando en tu registro. Las opciones que más ha utilizado nuestra tienda son PROTECT , CASCADE y SET_NULL . Aquí están las reglas básicas que he descubierto:

  1. Use PROTECT cuando su FK esté apuntando a una tabla de búsqueda que realmente no debería estar cambiando y que ciertamente no debería causar que su tabla cambie. Si alguien intenta eliminar una entrada en esa tabla de búsqueda, PROTECT evita que la elimine si está vinculada a algún registro. También evita que django elimine su registro solo porque eliminó una entrada en una tabla de búsqueda. Esta última parte es crítica. Si alguien eliminara el género "Femenino" de mi tabla de Género, CIERTAMENTE NO querría que eso elimine instantáneamente a todas las personas que tenía en mi tabla de Persona que tenían ese género.
  2. Use CASCADE cuando su FK esté apuntando a un registro "padre". Por lo tanto, si una persona puede tener muchas entradas PersonEthnicity (él / ella puede ser indio americano, negro y blanco), y esa persona se elimina, realmente me gustaría que se eliminen las entradas "child" PersonEthnicity. Son irrelevantes sin la Persona.
  3. Use SET_NULL cuando desee que se permita a las personas eliminar una entrada en una tabla de búsqueda, pero aún así desea conservar su registro. Por ejemplo, si una persona puede tener una escuela secundaria, pero realmente no me importa si esa escuela secundaria desaparece en mi tabla de búsqueda, diría on_delete=SET_NULL . Esto dejaría mi registro de Persona ahí afuera; solo establecería el FK de la escuela secundaria en mi Persona como nulo. Obviamente, tendrá que permitir null=True en ese FK.

Aquí hay un ejemplo de un modelo que hace las tres cosas:

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''

Como último dato, ¿sabía que si no especifica on_delete (o no lo hizo), el comportamiento predeterminado es CASCADE ? Esto significa que si alguien eliminó una entrada de género en su tabla de Género, ¡cualquier registro de Persona con ese género también se eliminará!

Yo diría: "En caso de duda, configure on_delete=models.PROTECT ". Luego prueba tu aplicación. Rápidamente descubrirá qué FK deben etiquetarse como otros valores sin poner en peligro ninguno de sus datos.

Además, vale la pena señalar que on_delete=CASCADE realidad no se agrega a ninguna de sus migraciones, si ese es el comportamiento que está seleccionando. Supongo que esto se debe a que es el valor predeterminado, por lo que poner on_delete=CASCADE es lo mismo que no poner nada.


si está utilizando la clase primaria como su clave externa que necesita usar (nombre de la clase primaria, on_delete = models.CASCADE), entonces, si elimina el modelo de la clase primaria, eliminará automáticamente los datos de la clase secundaria asociados con esa clase primaria.


django==1.11.22 tiene el siguiente código. Significa que on_delete defecto es CASCADE .

class ForeignKey(ForeignObject): ....... if on_delete is None: warnings.warn( "on_delete will be a required arg for %s in Django 2.0. Set " "it to models.CASCADE on models and in existing migrations " "if you want to maintain the current default behavior. " "See https://docs.djangoproject.com/en/%s/ref/models/fields/" "#django.db.models.ForeignKey.on_delete" % ( self.__class__.__name__, get_docs_version(), ), RemovedInDjango20Warning, 2) on_delete = CASCADE .......


Aquí está la respuesta a su pregunta que dice: ¿por qué usamos on_delete?

Cuando se elimina un objeto al que hace referencia una ForeignKey, Django emula de manera predeterminada el comportamiento de la restricción de SQL ON DELETE CASCADE y también elimina el objeto que contiene la ForeignKey. Este comportamiento se puede anular especificando el argumento on_delete. Por ejemplo, si tiene una ForeignKey anulable y desea que se establezca como nula cuando se elimina el objeto al que se hace referencia:

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

Los valores posibles para on_delete se encuentran en django.db.models:

CASCADA: elimina en cascada; el valor por defecto.

PROTEGER: Evita la eliminación del objeto al que se hace referencia al proteger ProtectedError, una subclase de django.db.IntegrityError.

SET_NULL: establece el ForeignKey nulo; esto solo es posible si null es True.

SET_DEFAULT: establece ForeignKey en su valor predeterminado; se debe establecer un valor predeterminado para ForeignKey.