2010-12-09 29 views
24

在Django中,如果模型中有ImageFile,则删除操作将从磁盘中删除关联的文件以及从数据库中删除记录。替换Django映像并不会删除原始文件

不应该替换图像也从磁盘中删除不需要的文件?相反,我发现它保留了原来的内容并添加了替换。

现在删除对象不会删除原来的文件只替换。

有没有什么好的策略来做到这一点?如果我的用户经常替换他们的图片,我不想拥有一堆孤儿文件。

+0

您是否尝试过在模型上使用保存方法来检查文件是否正在更新并在必要时删除旧文件? – PhoebeB 2010-12-09 12:06:11

+0

我有一个[类似的问题,并添加了一个问题](http://stackoverflow.com/q/4787141/207894)。你可能会在接下来的几天里发现你正在寻找的东西... – 2011-01-25 00:17:16

回答

0

我用一个简单的方法与popen,所以,当我救我Info模型我链接到新的前删除原文件:

import os 

try: 
    os.popen("rm %s" % str(info.photo.path)) 
except: 
    #deal with error 
    pass 
info.photo = nd['photo'] 
1

已经有一些门票就这个问题虽然是这很可能不会成为核心。最全面的是http://code.djangoproject.com/ticket/11663。如果您正在寻找解决方案,补丁和票据评论可以为您提供一些指导。

您也可以考虑使用不同的StorageBackend,如由Django片段976给出的覆盖文件存储系统。http://djangosnippets.org/snippets/976/。您可以将默认存储器更改为此后端,或者可以在每个FileField/ImageField声明中覆盖它。

+0

我认为976代码存在问题。考虑一个UserProfile模型,它具有使用这个OverwriteStorage后端的配置文件映像字段,upload_to =“%Y /%米/%d”。两位用户在同一天上传一张名为“me.jpg”的个人资料照片。第一次上传将在2012/02/11/me.jpg进行。第二个上传将删除并替换此图像,并使两个UserProfile图像字段引用相同的图像。 – chris 2012-02-11 10:24:45

+0

OverwriteStorage的预期行为是替换文件。这意味着确保名称的唯一性落在网站开发者身上,而不是后端。 – 2012-02-11 13:14:44

24

我发现最好的策略就是让自定义的保存方法的模型:

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中,无论如何,你必须添加更多的自定义代码来做到这一点(或定期做一些肮脏的cron工作)。

最后使用您的ForeignKey,ManytoMany和其他关系来检查所有更新/删除案例,以检查后端文件是否被正确删除。 只相信你测试的

+2

在2个网站使用了近3年后,我可以证实这种方法已经准备就绪,并且没有任何问题。我现在在Django 1.6.2的第三个网站中使用这种方法。它仍然很好。 – 2014-02-24 00:07:03

+0

在django 1.9中使用`ModelAdmin`类的`save_model()`和`delete_model()`函数,它的工作就像一个魅力 – samix73 2016-05-24 13:01:32

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 

而且随着ImageField的使用它,像这样:

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) 
2

如果不使用事务或者你就不怕事务回滚丢失的文件,您可以使用django-cleanup

12

不应该替换图像还从磁盘中删除不需要的文件?

在过去的日子里,FileField渴望清理孤儿文件。但是,这改变了Django 1.2

在早期的Django版本,当被删除包含的FileField模型实例,FileField或把它自身也删除后端存储的文件。这为几个潜在的严重数据丢失情况打开了大门,包括回滚事务和引用同一文件的不同模型上的字段。在Django 1.2.5中,FileField永远不会从后端存储中删除文件。

1

这里是一个可以使用或不upload_to=...blank=True工作代码,并在提交的文件具有相同的名称作为旧的。

(PY 3语法上的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) 

请记住,如果你在一个非事务上下文这种解决方案仅适用(无回退,因为该文件明确丢失)

相关问题