Replacing a Django image doesn't delete original

前端 未结 8 1301
死守一世寂寞
死守一世寂寞 2020-12-13 14:43

In Django, if you have a ImageFile in a model, deleting will remove the associated file from disk as well as removing the record from the database.

Shouldn\'t replac

相关标签:
8条回答
  • 2020-12-13 15:00

    Here is a code that can work with or without upload_to=... or blank=True, and when the submitted file has the same name as the old one.

    (py3 syntax, tested on Django 1.7)

    class Attachment(models.Model):
    
        document = models.FileField(...)  # or ImageField
    
        def delete(self, *args, **kwargs):
            self.document.delete(save=False)
            super().delete(*args, **kwargs)
    
        def save(self, *args, **kwargs):
            if self.pk:
                old = self.__class__._default_manager.get(pk=self.pk)
                if old.document.name and (not self.document._committed or not self.document.name):
                    old.document.delete(save=False)
            super().save(*args, **kwargs)
    

    Remember that this kind of solution is only applicable if you are in a non transactional context (no rollback, because the file is definitively lost)

    0 讨论(0)
  • 2020-12-13 15:01

    If you don't use transactions or you don't afraid of loosing files on transaction rollback, you can use django-cleanup

    0 讨论(0)
  • 2020-12-13 15:03

    Shouldn't replacing an image also remove the unneeded file from disk?

    In the olden days, FileField was eager to clean up orphaned files. But that changed in Django 1.2:

    In earlier Django versions, when a model instance containing a FileField was deleted, FileField took it upon itself to also delete the file from the backend storage. This opened the door to several potentially serious data-loss scenarios, including rolled-back transactions and fields on different models referencing the same file. In Django 1.2.5, FileField will never delete files from the backend storage.

    0 讨论(0)
  • 2020-12-13 15:06

    I save the original file and if it has changed - delete it.

    class Document(models.Model):
        document = FileField()
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self._document = self.document
    
        def save(self, *args, **kwargs):
            if self.document != self._document:
                self._document.delete()
                super().save(*args, **kwargs)
    
    0 讨论(0)
  • 2020-12-13 15:08

    There have been a number of tickets regarding this issue though it is likely this will not make it into the core. The most comprehensive is http://code.djangoproject.com/ticket/11663. The patches and ticket comments can give you some direction if you are looking for a solution.

    You can also consider using a different StorageBackend such as the Overwrite File Storage System given by Django snippet 976. http://djangosnippets.org/snippets/976/. You can change your default storage to this backend or you can override it on each FileField/ImageField declaration.

    0 讨论(0)
  • 2020-12-13 15:08

    I used a simple method with popen, so when i save my Info model i delete the former file before linking to the new:

    import os
    
    try:
        os.popen("rm %s" % str(info.photo.path))
    except:
        #deal with error
        pass
    info.photo = nd['photo']
    
    0 讨论(0)
提交回复
热议问题