替换Django图片时未删除原始文件
在Django中,如果你的模型里有一个ImageFile,删除这个记录时,会同时把磁盘上的文件也删掉,数据库里的记录也会被删除。
那么,替换一张图片时,难道不应该把不需要的文件也从磁盘上删除吗?可是我发现,它会保留原来的文件,并且把新的文件加上去。
这样一来,删除这个对象时,只会删除新替换的文件,而原来的文件却不会被删掉。
有没有什么好的方法来解决这个问题呢?我不想让我的用户频繁替换图片后,留下很多无用的文件。
8 个回答
下面这个示例代码的功能是,当你在一个图片字段(ImageField)里上传一张图片时,它会检查是否有同名的文件存在。如果有的话,它会先删除那个旧文件,然后再保存新的文件。
这个代码也可以很简单地修改成无论文件名是什么都删除旧文件,但我在我的项目里并不想这样做。
你可以添加下面这个类:
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
然后像这样使用它和图片字段:
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)
替换图片的时候,难道不应该把不需要的文件也从磁盘上删除吗?
在以前的版本中,FileField
会主动清理那些孤立的文件。但是在Django 1.2之后,这种情况发生了变化:
在早期的Django版本中,当一个包含FileField的模型实例被删除时,FileField会自动把后端存储中的文件也删除。这就可能导致一些严重的数据丢失问题,比如事务回滚和不同模型的字段引用同一个文件。在Django 1.2.5中,FileField将不会再从后端存储中删除文件。
我发现的最好方法是在模型里创建一个自定义的保存方法:
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)
需要注意的是,就像更新操作不会删除后端文件一样,删除一个实例模型(这里是照片)也不会删除后端文件,尤其是在Django 1.3版本中。你需要添加更多的自定义代码来实现这一点(或者定期做一些麻烦的定时任务)。
最后,测试你所有的更新和删除操作,特别是涉及到外键、多个关系等,确保后端文件被正确删除。只相信你测试过的结果。