Luego de consultar especialistas en el tema, programadores de deferentes ramas y profesores hemos dado con la respuesta al problema y la compartimos en esta publicación.
Solución:
Lo hace:
El método delete() realiza una eliminación masiva y no llama a ningún método delete() en sus modelos. Sin embargo, emite las señales pre_delete y post_delete para todos los objetos eliminados (incluidas las eliminaciones en cascada).
Para que eso funcione, puede anular el método de eliminación en QuerySet
, y luego aplicar eso QuerySet
como gerente:
class ImageQuerySet(models.QuerySet):
def delete(self, *args, **kwargs):
for obj in self:
obj.img.delete()
super(ImageQuerySet, self).delete(*args, **kwargs)
class Image(models.Model):
objects = ImageQuerySet.as_manager()
img = models.ImageField(upload_to=get_image_path)
...
def delete(self, *args, **kwargs):
self.img.delete()
super(Image, self).delete(*args, **kwargs)
El método de eliminación de queryset funciona directamente en la base de datos. no llama Model.delete()
métodos. De los documentos:
Tenga en cuenta que, siempre que sea posible, esto se ejecutará exclusivamente en SQL, por lo que los métodos delete() de instancias de objetos individuales no se llamarán necesariamente durante el proceso. Si proporcionó un método delete() personalizado en una clase de modelo y desea asegurarse de que se llame, deberá eliminar “manualmente” las instancias de ese modelo (por ejemplo, iterando sobre un QuerySet y llamando a delete() en cada objeto individualmente) en lugar de usar el método de eliminación masiva () de un QuerySet.
Si desea anular el comportamiento predeterminado de la interfaz de administración de Django, puede escribir un delete
acción:
https://docs.djangoproject.com/en/1.7/ref/contrib/admin/actions/
Otro método es anular post_delete
(o pre_delete
) señal en lugar de delete
método:
https://docs.djangoproject.com/en/1.7/ref/signals/#django.db.models.signals.post_delete
Como pre_delete, pero enviado al final del método delete() de un modelo y el método delete() de un conjunto de consultas.
Creo que este problema se aborda en los documentos.
En donde dice:
Los métodos de modelo anulados no se llaman en operaciones masivas
Tenga en cuenta que el método delete() para un objeto no se llama necesariamente cuando se eliminan objetos de forma masiva mediante un QuerySet o como resultado de una eliminación en cascada. Para garantizar que se ejecute la lógica de eliminación personalizada, puede usar señales pre_delete y/o post_delete.
Desafortunadamente, no hay una solución cuando se crean o actualizan objetos en masa, ya que no se llama a save(), pre_save y post_save.
Como se sugiere en los documentos anteriores, creo que una mejor solución es usar el post_delete
señal, así:
from django.db.models.signals import post_delete
from django.dispatch import receiver
class Image(models.Model):
img = models.ImageField(upload_to=get_image_path)
...
@receiver(post_delete, sender=Image)
def delete_image_hook(sender, instance, using, **kwargs):
instance.img.delete()
A diferencia de anular el delete
método, el delete_image_hook
La función debe llamarse también en eliminaciones masivas y eliminaciones en cascada. Aquí hay más información sobre el uso de las señales de Django: https://docs.djangoproject.com/en/1.11/topics/signals/#connecting-to-signals-sent-by-specific-senders
Nota sobre las respuestas anteriores:
Algunas de las publicaciones anteriores sugieren anular el delete
método de QuerySet, que puede tener implicaciones en el rendimiento y otros comportamientos no deseados. Quizás esas respuestas se escribieron antes de que se implementaran las Señales de Django, pero creo que usar Señales es un enfoque más limpio.
Reseñas y puntuaciones
Si piensas que ha sido de provecho nuestro artículo, sería de mucha ayuda si lo compartes con más entusiastas de la programación así nos ayudas a extender esta información.