djangodjango-models

Django delete FileField


I'm building a web app in Django. I have a model that uploads a file, but I can not delete the file. Here is my code:

class Song(models.Model):
    name = models.CharField(blank=True, max_length=100)
    author = models.ForeignKey(User, to_field='id', related_name="id_user2")
    song = models.FileField(upload_to='/songs/')
    image = models.ImageField(upload_to='/pictures/', blank=True)
    date_upload = models.DateField(auto_now_add=True)

    def delete(self, *args, **kwargs):
        # You have to prepare what you need before delete the model
        storage, path = self.song.storage, self.song.path
        # Delete the model before the file
        super(Song, self).delete(*args, **kwargs)
        # Delete the file after the model
        storage.delete(path)

Then, in python manage.py shell I do this:

song = Song.objects.get(pk=1)
song.delete()

It deletes the record from the database but not the file on server. What else can I try?

Thanks!


Solution

  • Before Django 1.3, the file was deleted from the filesystem automatically when you deleted the corresponding model instance. You are probably using a newer Django version, so you'll have to implement deleting the file from the filesystem yourself.

    Simple signal-based sample

    My method of choice at the time of writing is a mix of post_delete and pre_save signals, which makes it so that obsolete files are deleted whenever corresponding models are deleted or have their files changed.

    Based on a hypothetical MediaFile model:

    import os
    import uuid
    
    from django.db import models
    from django.dispatch import receiver
    from django.utils.translation import ugettext_lazy as _
    
    
    class MediaFile(models.Model):
        file = models.FileField(_("file"),
            upload_to=lambda instance, filename: str(uuid.uuid4()))
    
    
    # These two auto-delete files from filesystem when they are unneeded:
    
    @receiver(models.signals.post_delete, sender=MediaFile)
    def auto_delete_file_on_delete(sender, instance, **kwargs):
        """
        Deletes file from filesystem
        when corresponding `MediaFile` object is deleted.
        """
        if instance.file:
            if os.path.isfile(instance.file.path):
                os.remove(instance.file.path)
    
    @receiver(models.signals.pre_save, sender=MediaFile)
    def auto_delete_file_on_change(sender, instance, **kwargs):
        """
        Deletes old file from filesystem
        when corresponding `MediaFile` object is updated
        with new file.
        """
        if not instance.pk:
            return False
    
        try:
            old_file = MediaFile.objects.get(pk=instance.pk).file
        except MediaFile.DoesNotExist:
            return False
    
        new_file = instance.file
        if not old_file == new_file:
            if os.path.isfile(old_file.path):
                os.remove(old_file.path)
    

    Addendum: periodic cleanup

    Realistically, you may want to also run a periodic task to handle orphan file cleanup in case a runtime failure prevents some file from being removed. With that in mind, you could probably get rid of signal handlers altogether, and make such a task the mechanism for dealing with insensitive data and not-so-large files.

    Either way though, if you are handling sensitive data, it’s always better to double- or triple- check that you never fail to timely delete data in production to avoid any associated liabilities.

    See also