Estoy bastante familiarizado con Django, pero recientemente noté que existe una on_delete=models.CASCADE
opción 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.
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é models.CASCADE
hacer? ( 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?
python
django
django-models
Todo es variedad
fuente
fuente
Respuestas:
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 SQL:CASCADE
.PROTECT
: Prohibir la eliminación del objeto referenciado. Para eliminarlo, deberá eliminar todos los objetos que lo referencian manualmente. Equivalente SQL:RESTRICT
.SET_NULL
: Establezca 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 SQL:SET NULL
.SET_DEFAULT
: Establece el valor predeterminado. Equivalente 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 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 aSET_NULL
menudo son útiles EstablecerCASCADE
donde no debería, potencialmente puede eliminar toda su base de datos en cascada, simplemente eliminando un solo usuario.Nota adicional para aclarar la dirección de la cascada
Es divertido notar que la dirección de la
CASCADE
acción no está clara para muchas personas. En realidad, es divertido notar que solo laCASCADE
acción no está clara. Entiendo que el comportamiento en cascada puede ser confuso, sin embargo, debe pensar que es la misma dirección que cualquier otra acción . Por lo tanto, si siente que laCASCADE
dirección no es clara para usted, en realidad significa que elon_delete
comportamiento no es claro para usted.En su base de datos, una clave foránea está representada básicamente por un campo entero cuyo valor es la clave primaria del objeto foráneo. Supongamos que tiene una entrada comment_A , que tiene una clave foránea para una entrada article_B . Si elimina la entrada comment_A , todo está bien, article_B utiliza para vivir sin comment_A y no se molestan si se elimina. Sin embargo, si se elimina article_B , entonces comment_A pánico! Nunca vivió sin article_B y lo necesita, es parte de sus atributos (
article=article_B
pero ¿qué es * article_B ** ???). Aquí es dondeon_delete
interviene, para determinar cómo resolver este error de integridadya sea diciendo:PROTECT
en lenguaje SQL)SET_NULL
)CASCADE
comportamiento).SET_DEFAULT
o inclusoSET(...)
).DO_NOTHING
)Espero que aclare la dirección de la cascada. :)
fuente
Comment
tiene una clave externa paraBlogPost
eliminar BlogPost, debería eliminar Comentario, pero eliminar Comentario no debería eliminar BlogPost, independientemente del RDMS.Comment
quien tiene el campo FK en su tabla, mientras queBlogPost
"posee"Comment
si hablamos del modelo de la vida real. Bueno.El
on_delete
método se usa para decirle a Django qué hacer con las instancias del modelo que dependen de la instancia del modelo que elimine. (por ejemplo, unaForeignKey
relación). Elon_delete=models.CASCADE
dice Django en cascada el efecto de borrado es decir, seguir borrando los modelos dependientes también.Aquí hay un ejemplo más concreto. Suponga que tiene un
Author
modelo que esForeignKey
unBook
modelo. Ahora, si elimina una instancia delAuthor
modelo, Django no sabría qué hacer con las instancias delBook
modelo que dependen de esa instancia delAuthor
modelo. Elon_delete
método le dice a Django qué hacer en ese caso. La configuración leon_delete=models.CASCADE
indicará a Django que ponga en cascada el efecto de eliminación, es decir, elimine todas lasBook
instancias del modelo que dependen de laAuthor
instancia del modelo que eliminó.Nota:
on_delete
se convertirá en un argumento obligatorio en Django 2.0. En versiones anteriores, su valor predeterminado esCASCADE
.Aquí está toda la documentación oficial.
fuente
Para su información, el
on_delete
parámetro en los modelos es al revés de lo que parece. Poneson_delete
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. La opciones de nuestra tienda han utilizado la mayoría sonPROTECT
,CASCADE
ySET_NULL
. Aquí están las reglas básicas que he descubierto: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.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.SET_NULL
cuando no quiere que la gente se les permitirá borrar una entrada en una tabla de consulta, pero aún 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 mesa de consulta, diríaon_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ás que permitirnull=True
ese FK.Aquí hay un ejemplo de un modelo que hace las tres cosas:
Como último dato, ¿sabía que si no especifica
on_delete
(o no lo hizo), el comportamiento predeterminado esCASCADE
? 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, listo
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 en
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 poneron_delete=CASCADE
es lo mismo que no poner nada.fuente
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
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 muchos motivos. 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 informes o en cualquier lugar donde el usuario pueda acceder desde el front-end, excluye cualquier cosa que sea
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.
fuente
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:
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.
fuente
Digamos que tiene dos modelos, uno llamado Persona y otro llamado Empresas .
Por definición, una persona puede crear más de una empresa.
Teniendo en cuenta que una empresa puede tener una sola persona, queremos que cuando se elimine a una persona, también se eliminen todas las empresas asociadas con esa persona.
Entonces, comenzamos creando un modelo de Persona, como este
Entonces, el modelo de Empresas puede verse así
Observe el uso de
on_delete=models.CASCADE
en las empresas modelo. Es decir, eliminar todas las empresas cuando se elimina la persona que lo posee (instancia de la clase Persona).fuente
Reoriente su modelo mental de la funcionalidad de "CASCADA" pensando en agregar un FK a una cascada ya existente (es decir, una cascada). La fuente de esta cascada es una clave primaria. Los borrados fluyen hacia abajo.
Por lo tanto, si define on_delete de un FK como "CASCADE", está agregando el registro de este FK a una cascada de eliminaciones que se originan en el PK. El registro de FK puede participar en esta cascada o no ("SET_NULL"). De hecho, un registro con un FK puede incluso evitar el flujo de las eliminaciones. Construye una presa con "PROTEGER".
fuente
Usar CASCADE significa en realidad decirle a Django que elimine el registro referenciado. En el ejemplo de la aplicación de encuesta a continuación: Cuando se elimina una 'Pregunta', también se eliminarán las Opciones que tiene esta Pregunta.
p. ej. Pregunta: ¿Cómo se enteró de nosotros? (Opciones: 1. Amigos 2. Anuncio de TV 3. Motor de búsqueda 4. Promoción de correo electrónico)
Cuando elimine esta pregunta, también eliminará todas estas cuatro opciones de la tabla. Tenga en cuenta en qué dirección fluye. No tiene que poner on_delete = models.CASCADE en Question Model póngalo en la opción.
fuente