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.
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
.
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:
-
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. -
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. -
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í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á que permitirnull=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.