Tengo un problema porque estoy eliminando un widget usando some_widget_instance.delete (). También tengo un modelo llamado WidgetFile con un método de anulación delete () para poder eliminar archivos de mi disco duro cuando se elimina un WidgetFile. El problema que tengo es que si elimino un Widget y tiene WidgetFiles relacionados de esta manera:

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

Bueno, cuando elimino ese Widget, se eliminan los WidgetFiles, pero el método delete () no se dispara y hace mis cosas adicionales en el disco duro. Cualquier ayuda es muy apreciada.

28
orokusaki 8 oct. 2009 a las 04:31

8 respuestas

La mejor respuesta

Me lo imaginé. Acabo de poner esto en ese modelo de Widget:

def delete(self):
    files = WidgetFile.objects.filter(widget=self)
    if files:
        for file in files:
            file.delete()
    super(Widget, self).delete()

Esto activó el método delete () necesario en cada uno de los objetos relacionados, activando así mi código de eliminación de archivo personalizado. Es más costoso en la base de datos, sí, pero cuando intentas eliminar archivos en un disco duro de todos modos, no es un gasto tan grande llegar a la base de datos unas cuantas veces más.

36
orokusaki 31 mar. 2014 a las 01:22

Desde Django 1.9, si solo definiera on_delete=models.CASCADE para el campo, eliminará todos los objetos relacionados al eliminarlos.

-1
CLTanuki 8 abr. 2016 a las 22:11

¿some_widget_instance es una instancia de Widget o de WidgetFile? Porque si es una instancia de Widget, no obtendrá su función personalizada delete(), que está en la clase WidgetFile.

0
thornomad 8 oct. 2009 a las 00:44

Solo para solucionar este problema: pre-eliminar señal. (De ninguna manera implica que no haya una solución real).

1
che 8 oct. 2009 a las 01:04

Esto solo parece estar lleno de sentido si un Widget está conectado a un WidgetFile exactamente. En ese caso, debe usar un OneToOneField

De Ejemplos individuales:

# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)
>>> r.delete()
1
vikingosegundo 8 oct. 2009 a las 00:52

Usando clear() antes de eliminar, elimina todos los objetos del conjunto de objetos relacionados.

Ver django-following-relationships-backward

Ejemplo:

group.link_set.clear() 
group.delete() 
3
panchicore 8 oct. 2009 a las 03:21

Estoy haciendo lo mismo y noté una pepita en los documentos de Django en la que deberías pensar.

Anulación de métodos de modelo predefinidos

Anulación de Eliminar Tenga en cuenta que el método delete () para un objeto no se llama necesariamente al eliminar objetos en masa utilizando un QuerySet. Para garantizar que se ejecute la lógica de eliminación personalizada, puede usar las señales pre_delete y / o post_delete.

Esto significa que su fragmento no siempre hará lo que quiere. Usar Signals es una mejor opción para lidiar con las eliminaciones.

Fui con lo siguiente:

import shutil
from django.db.models.signals import pre_delete 
from django.dispatch import receiver

@receiver(pre_delete)
def delete_repo(sender, instance, **kwargs):
    if sender == Set:
        shutil.rmtree(instance.repo)
76
ElementalVoid 1 oct. 2012 a las 18:20