Cleanup Files (and Images) On Model Delete in Django

In Django, if your model has Filefield / Imagefield, when it's get deleted it doesn't delete attached files by default. To fix that you need to do two steps: 1) Add filecleanup function, that'll take care of deleting files attached to a model:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  1. import os
  2. from django.core.files.storage import default_storage
  3. from django.db.models import FileField
  4. def file_cleanup(sender, **kwargs):
  5. """
  6. File cleanup callback used to emulate the old delete
  7. behavior using signals. Initially django deleted linked
  8. files when an object containing a File/ImageField was deleted.
  9. Usage:
  10. >>> from django.db.models.signals import post_delete
  11. >>> post_delete.connect(file_cleanup, sender=MyModel, dispatch_uid="mymodel.file_cleanup")
  12. """
  13. for fieldname in sender._meta.get_all_field_names():
  14. try:
  15. field = sender._meta.get_field(fieldname)
  16. except:
  17. field = None
  18. if field and isinstance(field, FileField):
  19. inst = kwargs['instance']
  20. f = getattr(inst, fieldname)
  21. m = inst.__class__._default_manager
  22. if hasattr(f, 'path') and os.path.exists(f.path)\
  23. and not m.filter(**{'%s__exact' % fieldname: getattr(inst, fieldname)})\
  24. .exclude(pk=inst._get_pk_val()):
  25. try:
  26. default_storage.delete(f.path)
  27. except:
  28. pass

2) In your model.py, add post_delete signal to catch model deletion event:

1
2
3
4
5
6
7
  1. from django.db import models
  2. from django.db.models.signals import post_delete
  3. from .utils import file_cleanup
  4. ... models code goes here ...
  5. post_delete.connect(file_cleanup, sender=Image, dispatch_uid="gallery.image.file_cleanup")

And that's all. As you see on example above, my sender is Image model and when it's get deleted, it'll fire file_cleanup function that will take care of cleaning up files.