🐍 Cleanup Django media files from disk when deleting them
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!