【问题标题】:How to delete old image when update ImageField?更新 ImageField 时如何删除旧图像?
【发布时间】:2011-02-22 03:18:27
【问题描述】:

我正在使用 Django 创建一个股票照片网站,我的模型中有一个 ImageField,问题是当用户更新图像字段时,原始图像文件没有从硬盘中删除。

如何在更新后删除旧图像?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    使用django-cleanup

    pip install django-cleanup
    

    settings.py

    INSTALLED_APPS = (
        ...
        'django_cleanup.apps.CleanupConfig', # should be placed after your apps
    
    )
    

    【讨论】:

    • 这是最好的选择
    • 这太棒了。顺便说一句,正如官方文档中所述,您应该将'django_cleanup.apps.CleanupConfig' 放入您的 INSTALLED_APPS 列表中。
    • 这样的救星。应该是 Django imo 中的默认行为。
    【解决方案2】:

    我所做的是保存旧图像的路径,如果表单有效,我将删除旧图像。

    if request.method == 'POST':
            old_image = ""
            if request.user.profile.profile_picture:
                old_image = request.user.profile.profile_picture.path
            form = UpdateProfileForm(request.POST,request.FILES,instance = profile)
            if form.is_valid():
                if os.path.exists(old_image):
                    os.remove(old_image)
            form.save()
    

    有点乱,但你没有安装第三方或任何东西

    【讨论】:

      【解决方案3】:

      您必须手动删除旧图像。

      图像的绝对路径存储在your_image_field.path 中。所以你会做这样的事情:

      os.remove(your_image_field.path)
      

      但是,为方便起见,您可以使用关联的 FieldFile 对象,它可以轻松访问底层文件,并提供一些方便的方法。见http://docs.djangoproject.com/en/dev/ref/models/fields/#filefield-and-fieldfile

      【讨论】:

      • 这不是 django ImageField 的默认行为吗?基于这篇文章:redrobotstudios.com/blog/2010/03/02/…?
      • OP 询问是否使用 ImageField 更新模型实例(即用户上传新图像)。在这种情况下,旧图像不会被删除。
      • 注意:我不确定从那以后它是否发生了变化,或者这是否略有偏差,但在 1.6 中,imgfield.name 是一个相对路径。 imgfield.file.name 具有完整路径。
      • name 属性返回项目根目录的相对路径,我认为使用url 属性更好。
      • @AK12 - 更好的是path - 这是文件系统上图像的绝对路径。我想知道 API 是否在过去 10.5 年发生了变化,name 曾经这样做过。无论哪种方式,我都更新了答案以建议改用path
      【解决方案4】:

      试试这个,即使删除旧文件也能正常工作

      def logo_file(instance, filename):
      
          try:
              this = business.objects.get(id=instance.id)
              if this.logo is not None:
                  path = "%s" % (this.logo)
                  os.remove(path)
          finally:
              pass..
      

      即使没有“try .. finally”,代码也可以工作,但如果文件被意外删除,它会产生问题。 更改:在“try”中移动模型匹配,这样它就不会在用户注册时抛出任何错误 如果有任何问题,请告诉我。

      【讨论】:

        【解决方案5】:

        完成 Chris Lawlor 的回答,尝试了这个并且有效。

        from YOURAPP.settings import BASE_DIR
        
        try:
            os.remove(BASE_DIR + user.userprofile.avatarURL)
        except Exception as e:
            pass 
        

        网址的格式为/media/mypicture.jpg

        【讨论】:

          【解决方案6】:

          您可以在模型中定义pre_save 接收者:

          @receiver(models.signals.pre_save, sender=UserAccount)
          def delete_file_on_change_extension(sender, instance, **kwargs):
              if instance.pk:
                  try:
                      old_avatar = UserAccount.objects.get(pk=instance.pk).avatar
                  except UserAccount.DoesNotExist:
                      return
                  else:
                      new_avatar = instance.avatar
                      if old_avatar and old_avatar.url != new_avatar.url:
                          old_avatar.delete(save=False)
          

          我的头像对每个人都有唯一的网址,例如“头像/ceb47779-8833-4719-8711-6f4e5cabb2b2.png”。如果用户上传具有不同扩展名的新图像,如 jpg,delete_file_on_change_extension 接收者删除旧图像,然后使用 url “avatars/ceb47779-8833-4719-8711-6f4e5cabb2b2.jpg”(在这种情况下)保存新图像。如果用户上传具有相同扩展名的新图像 django 会覆盖存储(磁盘)上的旧图像,因为图像路径是相同的。 这适用于 AWS S3 django-storage。

          【讨论】:

            【解决方案7】:

            在更新模型实例之前,可以使用FileField对象的delete方法。例如,如果FileFieldImageField 被命名为photo 并且您的模型实例是profile,那么以下将从磁盘中删除文件

            profile.photo.delete(False)
            

            更多说明,这里是 django 文档

            https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.fields.files.FieldFile.delete

            【讨论】:

            • 对于那些想知道为什么要传递False 参数的人。是为了保证删除图片后模型不保存。
            【解决方案8】:

            这是一个默认删除孤立文件的应用程序:django-smartfields。 它会在任何时候删除文件:

            • 字段值已替换为新值(上传或手动设置)
            • 通过表单清除字段(当然,如果该字段不是必需的)
            • 包含该字段的模型实例本身被删除。

            可以使用以下参数关闭该清理功能:ImageField(keep_orphans=True) 以每个字段为基础,或在设置中全局设置 SMARTFIELDS_KEEP_ORPHANS = True

            from django.db import models
            
            from smartfields import fields
            
            class MyModel(models.Model):
                image = fields.ImageField()
                document = fields.FileField()
            

            【讨论】:

              【解决方案9】:

              在您的模型中使用此自定义保存方法:

              def save(self, *args, **kwargs):
                  try:
                      this = MyModelName.objects.get(id=self.id)
                      if this.MyImageFieldName != self.MyImageFieldName:
                          this.MyImageFieldName.delete()
                  except: pass
                  super(MyModelName, self).save(*args, **kwargs)
              

              它适用于我的网站。这个问题也困扰着我,我不想首先制作一个清理脚本而不是良好的簿记。如果有任何问题,请告诉我。

              【讨论】:

              • 你可能想使用:'this.MyImageFieldName.delete(save=False)' 因为我已经看到 delete() 递归调用'MyModelName'模型的'save',小心。 .. 并在 save 方法中使用 print 进行测试
              • 自己删除模型后也最好删除文件。如果由于任何原因删除模型失败,您不想丢失文件。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-10-30
              • 2020-11-19
              • 2018-04-24
              • 2011-07-18
              • 2019-11-25
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多