I'm overriding Django's model delete method in order to delete orphan files in the disk for image fields, something like this:
class Image(models.Model):
img = models.ImageField(upload_to=get_image_path)
...
def delete(self, *args, **kwargs):
self.img.delete()
super(Image, self).delete(*args, **kwargs)
This works fine when I delete single objects from the admin, but when I select multiple objects and delete them, this doesn't seem to get called. I have been googling for a while but haven't hit the right keywords to get the answer for this, nor the official documentation seems to talk about this subject.
It does:
The delete() method does a bulk delete and does not call any delete() methods on your models. It does, however, emit the pre_delete and post_delete signals for all deleted objects (including cascaded deletions).
For that to work, you can override delete method on QuerySet
, and then apply that QuerySet
as manager:
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)
Delete method of queryset works directly on the database. It does not call Model.delete()
methods. From the docs:
Keep in mind that this will, whenever possible, be executed purely in SQL, and so the delete() methods of individual object instances will not necessarily be called during the process. If you’ve provided a custom delete() method on a model class and want to ensure that it is called, you will need to “manually” delete instances of that model (e.g., by iterating over a QuerySet and calling delete() on each object individually) rather than using the bulk delete() method of a QuerySet.
If you want to override Django administration interface's default behavior, you can write a custom delete
action:
https://docs.djangoproject.com/en/1.7/ref/contrib/admin/actions/
Another method is to override post_delete
(or pre_delete
) signal instead of delete
method:
https://docs.djangoproject.com/en/1.7/ref/signals/#django.db.models.signals.post_delete
Like pre_delete, but sent at the end of a model’s delete() method and a queryset’s delete() method.