39

I have a django project in which the admins are able to upload media. As items sell, they are deleted from the site, thus removing their entry in the MySQL database. The images associated with the item, however, remain on the file system. This isn't neccessarily bad behavior - I don't mind keeping files around in case a deletion was an accident. The problem I forsee is two years from now, when storage space is limited because of a media folder bloated with old product images.

Does anyone know of a systematic/programmatic way to sort through ALL the images and compare them to the relevant MySQL fields, deleting any image which DOESN'T have a match from the filesystem? In the perfect world I'm imagining a button in the django-admin like "Clean-up unused media" which executes a python script capable of this behavior. I'll be sharing whatever my eventual solution is here, but what I'm looking for right now is anyone who has ideas, knows resources, or has done this at some point themselves.

Fabrizio A
  • 3,072
  • 5
  • 24
  • 35

5 Answers5

55

Try django-cleanup, it automatically invokes delete method on FileField when you remove model.

pip install django-cleanup

settings.py

INSTALLED_APPS = (
     ...
    'django_cleanup.apps.CleanupConfig', # should go after your apps
)
devlin31
  • 81
  • 10
un1t
  • 4,259
  • 2
  • 30
  • 33
  • Sometimes, I might want to host my website on the internet. I'm assuming that the hosting service provider's computer has everything needed to get my website to work beautifully on the internet. But how can I be sure that they have `django_cleanup` or not? and if they don't what should I do? – S.Ahmed Nov 19 '17 at 18:28
  • @S.Ahmed That's not the way hosting Django sites usually works. To use Django, you have to be able to install the packages you want. – Dustin Wyatt Oct 17 '22 at 17:10
16

django-unused-media will help you to clean old unused media by management command.

Very useful when you just started to use django-cleanup and already have files which needs to be deleted. Or if you have thumbnails which needs to be deleted from media directory.

Andrey Kolpakov
  • 446
  • 4
  • 7
4

Perhaps this is a bit late, but if you also want to know more about the problems that can appear with deletion, here's an article which explains how to delete them in two ways (with code snippets).

There is a management command which can be called every now and then, and a more "immediate" solution, using signals.

AdelaN
  • 3,366
  • 2
  • 25
  • 45
2

You can use signals. Than use os.remove() to clean up related files on delete.

This way your file system always reflects you db. No need for hitting some button.

allcaps
  • 10,945
  • 1
  • 33
  • 54
  • There is others problems by overriding delete method. If I have a ForeignKey on other model that it have an image field and ON_CASCADE DELETE ... that image don't delete itself. Another problem is the replace files. When I update one ImageField, the old files remain in my media folder.... What is the correct way of clean media folder from unused files?? – Fabrizio A Feb 21 '14 at 20:15
  • 2
    Don't use the delete method. Did you see this: http://stackoverflow.com/questions/4394194/replacing-a-django-image-doesnt-delete-original#answer-8342249 and https://github.com/un1t/django-cleanup – allcaps Feb 22 '14 at 20:17
  • If you're new to Django, using `os.remove()` might sound like a good idea, but it's not when you deploy. I'm not knocking this answer; I learned this the hard way. You won't usually keep user uploads on the deployed instance. Look into django's `default_storage.delete()` instead. – Jarad Oct 04 '21 at 22:25
1

The following is how I currently do it with Django 1.7 which need to be used from the start I don't know how you clean up unreferenced files in retrospect.

Say you've got an app named 'cars' and a model named 'Car'.

signals.py:

# cars/signals.py

from django.conf import settings
from django.dispatch import receiver
from django.db.models.signals import post_delete

from cars.models import Car

# By adding 'Car' as 'sender' argument we only receive signals from that model
@receiver(post_delete, sender=Car)
def on_delete(sender, **kwargs):
    instance = kwargs['instance']
    # ref is the name of the field file of the Car model
    # replace with name of your file field
    instance.ref.delete(save=False)

apps.py:

# cars/apps.py
from django.apps import AppConfig

class CarConfig(AppConfig):
    name = "cars"
    def ready(self):
        import cars.signals

__init__.py:

default_app_config = 'cars.apps.CarConfig'
Larpon
  • 812
  • 6
  • 19
  • What if a `Car` object *updates* it `ref` field, in that case, it might no longer point to the old media file, but your signal does not capture that. – Willem Van Onsem Jun 04 '19 at 10:50
  • 1
    @WillemVanOnsem - sorry but my answer is so old that I can't even recall what project I used this in. I'm not sure that *me* from the past was aware of any caveats :)) – Larpon Jun 07 '19 at 08:32