2009-06-17 19 views
23

Uno de mis modelos que tiene ForeignKey es en realidad una vista de MySQL en otras tablas. El problema que estoy corriendo en es que cuando se borra los datos de estas tablas, Django, tal como se describe en el "deleting objects" documentation ...¿Cómo creo un modelo de Django con ForeignKeys que no elimina en cascada elimina sus elementos secundarios?

When Django deletes an object, it emulates the behavior of the SQL constraint ON DELETE CASCADE -- in other words, any objects which had foreign keys pointing at the object to be deleted will be deleted along with it.

... trata de eliminar las filas de mi punto de vista, que por supuesto se puede 't, y así los tiros de error:

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

¿hay alguna manera de especificar una restricción ForeignKey en un modelo que me proporcionará toda la magia de Django, pero no se elimina en cascada sobre ella? 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?

Respuesta

18

respuesta de Harold me señaló en la dirección correcta. Este es un boceto en la forma en que implementé (en una base de datos heredada francés, por lo tanto, la convención de nombres poco extraño):

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() 
+2

Ver 'on_delete = models.SET_NULL': https://docs.djangoproject.com/en/1.4/ref/models/fields/#foreignkey (versión de sinze 1.3) – danihp

+2

¿Por qué' SET_NULL' ayuda? 'UPDATE' de una vista para establecer una clave foránea en NULL aún genera una excepción. 'models.DO_NOTHING' ayuda sin embargo. – jnns

2

Bueno, mirando método delete

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) 

diría anulando borrar debería ser suficiente ... código no probado habrí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) 
+0

(y sí, es un poco complicado, yo diría que no debería ser argumento para ForeignKey ... llenar una solicitud de función para él en sistema de tickets Django;)) De todos modos, para el caso de la vista , eche un vistazo a este error/parche: http://code.djangoproject.com/ticket/10829 – Almad

+0

olvidándose de eliminar el conjunto de consultas. –

1

Una forma es llamar al método claro antes de eliminar, documentation here que básicamente "borra" la relación. Un problema pensado: no es automático por 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 añadir el argumento de palabra clave para borrar, tal vez será en Django 1.3:? D

3

FYI - una solicitud de función para este existe en el repositorio de código 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, incluyendo desactivar el valor predeterminado ON DELETE CASCADE comportamiento.

+1

Sí, es hit 1.3 -> docs.djangoproject.com/en/dev/releases/1.3-alpha-1/#configurable-delete-cascade –

+0

Gracias por la actualización @stevejalim. Buenas noticias. Hace tiempo que quería esta función. – zlovelady

23

Django 1.3a1 y soporte esto por ForeignKey 's on_delete argumento.

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

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