Replacing a Django image doesn't delete original

前端 未结 8 1302
死守一世寂寞
死守一世寂寞 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:09

    The best strategy I've found is to make a custom save method in the model:

    class Photo(models.Model):
    
        image = ImageField(...) # works with FileField also
    
        def save(self, *args, **kwargs):
            # delete old file when replacing by updating the file
            try:
                this = Photo.objects.get(id=self.id)
                if this.image != self.image:
                    this.image.delete(save=False)
            except: pass # when new photo then we do nothing, normal case          
            super(Photo, self).save(*args, **kwargs)
    

    And beware, as with the updating which doesn't delete the back end file, deleting an instance model (here Photo) will not delete the back-end file, not in Django 1.3 anyway, you'll have to add more custom code to do that (or regularly do some dirty cron job).

    Finally test all your update/delete cases with your ForeignKey, ManytoMany and others relations to check if the back-end files are correctly deleted. Believe only what you test.

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

    The code in the following working example will, upon uploading an image in an ImageField, detect if a file with the same name exists, and in that case, delete that file before storing the new one.

    It could easily be modified so that it deletes the old file regardless of the filename. But that's not what I wanted in my project.

    Add the following class:

    from django.core.files.storage import FileSystemStorage
    class OverwriteStorage(FileSystemStorage):
        def _save(self, name, content):
            if self.exists(name):
                self.delete(name)
            return super(OverwriteStorage, self)._save(name, content)
    
        def get_available_name(self, name):
            return name
    

    And use it with ImageField like so:

    class MyModel(models.Model):
        myfield = models.ImageField(
            'description of purpose',
            upload_to='folder_name',
            storage=OverwriteStorage(),  ### using OverwriteStorage here
            max_length=500,
            null=True,
            blank=True,
            height_field='height',
            width_field='width'
        )
        height = models.IntegerField(blank=True, null=True)
        width = models.IntegerField(blank=True, null=True)
    
    0 讨论(0)
提交回复
热议问题