Stephen Gilmore

🐍 Cleanup Django media files from disk when deleting them

Django September 25th, 2023 2 minute read.

If you are using a Django file field and delete the object, by default, Django only deletes the database entry/reference to the object, it does not delete the file form disk. The best/easiest way to do that is through signals.

Let's say we have a simple "media" model object:

class Media(TimeStampedModel):  # pragma: no cover
    """A Django model for storing files"""

    file = models.FileField(upload_to="media/")

    @property
    def file_path(self) -> Path:
        """File path where media file was uploaded"""
        return Path(self.file.path)

    @property
    def file_name(self) -> str:
        """Name of the media file"""
        return self.file.name

To create the signal, we will create a new signals.py file in your app directory and add to it:

from media.models import Media

def delete_disk_file(sender, instance: Media, using, origin, **kwargs):
    """
    Signal to delete the file off the disk when it's deleted
    on the model.
    """
    disk_path = instance.file_path
    try:
        # Delete the file
        disk_path.unlink()
    except FileNotFoundError:
        # File is already gone
        ...

And then to implement the signal, it needs to be registered to the app in the apps.py file.

The apps.py file should look something like this out of the box:

from django.apps import AppConfig

class MediaConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "media"

The updated apps.py file with the signal will look like:

from django.apps import AppConfig
from django.db.models.signals import post_delete


class MediaConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "media"

    def ready(self):
        from media.models import Media
        from media.signals import delete_disk_file

        post_delete.connect(receiver=delete_disk_file, sender=Media)

Now go ahead and try it out. Try deleting a file from your database. The files should also now be removed from disk.

If you don't mind an extra dependency, there's also a package that will handle this for you named django-cleanup.

I hope this helps!