platzi partir modelos formularios datos crear avanzados mysql django django-models

mysql - partir - ¿Cómo creo un modelo de Django con ForeignKeys que no elimina en cascada las eliminaciones de sus hijos?



django base de datos (7)

Uno de mis modelos que tiene ForeignKey es en realidad una vista de MySQL en otras tablas. El problema al que me estoy enfrentando es que cuando borro datos de estas tablas, Django, como se describe en la documentación de "eliminación de objetos" ...

Cuando Django elimina un objeto, emula el comportamiento de la restricción SQL ON DELETE CASCADE - en otras palabras, cualquier objeto que tenga claves externas apuntando al objeto que se eliminará se eliminará junto con él.

... intenta eliminar filas de mi vista, lo que por supuesto no puede, y arroja el error:

mysql_exceptions.OperationalError ''>=(1395, "Can not delete from join view ''my_db.my_mysql_view''"''

¿Hay alguna forma de especificar una restricción ForeignKey en un modelo que me proporcione toda la magia de Django, pero no eliminará en cascada? O, ¿hay alguna manera de pedirle a MySQL que ignore los comandos para eliminar una fila de mi vista en lugar de generar un error?


Bueno, mirando el método de eliminación

def delete(self): assert self._get_pk_val() is not None, "%s object can''t be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) # Find all the objects than need to be deleted. seen_objs = CollectedObjects() self._collect_sub_objects(seen_objs) # Actually delete the objects. delete_objects(seen_objs)

Yo diría que anular la eliminación debería ser suficiente ... el código no probado sería

def delete(self): assert self._get_pk_val() is not None, "%s object can''t be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) # Find all the objects than need to be deleted. seen_objs = CollectedObjects() seen_objs.add(model=self.__class__, pk=self.pk, obj=self, parent_model=None) # Actually delete the objects. delete_objects(seen_objs)


Django 1.3a1 y superiores soportan esto a través del argumento on_delete ForeignKey .

El siguiente ejemplo establece el campo NULL al eliminar la clave externa. Vea la on_delete para más opciones.

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


El administrador ForeignKey de Django tiene un método llamado clear () que elimina todos los objetos del conjunto de objetos relacionados. Llamar a eso primero, luego eliminar tu objeto debería funcionar. Los objetos dependientes tendrán sus claves foráneas establecidas en Ninguno (si está permitido en su modelo).

Una breve descripción aquí: http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward


FYI - existe una solicitud de función para esto en el repositorio fuente de django en http://code.djangoproject.com/ticket/7539 . Parece que este tema está recibiendo algo de atención. Esperemos que se incluya en futuros lanzamientos de Django.

El ticket incluye parches en el núcleo de Django para implementar un parámetro opcional "on_delete" para los modelos.ForeignKey (...) que le permite especificar qué sucede cuando se borra el modelo apuntado, incluso desactivar el comportamiento ON DELETE CASCADE predeterminado.


La respuesta de Harold me indicó la dirección correcta. Este es un boceto sobre la forma en que lo implementé (en una base de datos heredada en francés, de ahí la convención de nomenclatura un tanto extraña):

class Factures(models.Model): idFacture = models.IntegerField(primary_key=True) idLettrage = models.ForeignKey(''Lettrage'', db_column=''idLettrage'', null=True, blank=True) class Paiements(models.Model): idPaiement = models.IntegerField(primary_key=True) idLettrage = models.ForeignKey(''Lettrage'', db_column=''idLettrage'', null=True, blank=True) class Lettrage(models.Model): idLettrage = models.IntegerField(primary_key=True) def delete(self): """Dettaches factures and paiements from current lettre before deleting""" self.factures_set.clear() self.paiements_set.clear() super(Lettrage, self).delete()



Una forma es llamar al método claro antes de eliminar, http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward "básicamente" borra la relación. Un problema pensado: no es automático en sí mismo. Puede elegir: llamarlo cada vez que no desee una cascada, o usar la señal de pre_delete para enviar mensajes claros antes de cada eliminación, por supuesto que le dará problemas cuando QUIERE eliminar - cascada.

O puede contribuir a la comunidad django y agregar el argumento de la palabra clave para eliminar, tal vez estará en django 1.3?: D