I/O 使用 'ImageKit' 对 django 中关闭的文件进行操作

I/O operation on closed file in django with 'ImageKit'

在我的 django 项目中,我使用 ImageKit 调整我的个人资料图片的大小。

我有一个包含这些字段的模型:

pasfoto = models.ImageField(upload_to='images/', blank=True)
pasfoto_thumbnail = ImageSpecField(source='pasfoto',
                                      processors=[ResizeToFill(150, 200)],
                                      format='JPEG',
                                      options={'quality': 60})

ImageSpecField 是从 Imagekit 导入的。

我正在通过 Django-storages 将图像保存在 amazon-S3 上

当我通过 UpdateView 呈现的模板(编辑表单)上传图像时,它会在成功后显示详细信息模板。 pasfoto_thumbnail 用于此模板,它是通过 Django 中基于 class 的 DetailView 呈现的。

在这种情况下,我看到一个错误 'I/O operation on closed file'。但在浏览器刷新后显示正确的图像。 发生了什么事,我该如何解决这个问题?


Django Debug page/info for this error

我最近遇到了同样的问题,它阻止我将 django-storages 升级到最新版本。

我终于找到了这个 old django-storages issue 的问题。

他们在那个帖子中提到了 django s3 storages。迁移到该库似乎可以解决问题。

我的旧项目和 Django 2 遇到了这个问题。我发现它发生在一些旧版本的包中。根据我从 github dependabot 获得的警报,对我的情况有帮助的是升级 django 和 pillow。

我 运行 pipenv install django=='2.2.24' pillow=='8.3.2' 我的问题已经解决了。

我正在使用 Django==3.2.13django-storages==1.12.3Pillow==9.1.1django-imagekit==4.1.0,并且不得不像这样覆盖默认存储:

class CustomS3Boto3Storage(S3Boto3Storage, ABC):
"""
This is our custom version of S3Boto3Storage that fixes a bug in
boto3 where the passed in file is closed upon upload.
From:
https://github.com/matthewwithanm/django-imagekit/issues/391#issuecomment-275367006
https://github.com/boto/boto3/issues/929
https://github.com/matthewwithanm/django-imagekit/issues/391
"""

def _save(self, name, content):
    """
    We create a clone of the content file as when this is passed to
    boto3 it wrongly closes the file upon upload where as the storage
    backend expects it to still be open
    """
    # Seek our content back to the start
    content.seek(0, os.SEEK_SET)

    # Create a temporary file that will write to disk after a specified
    # size. This file will be automatically deleted when closed by
    # boto3 or after exiting the `with` statement if the boto3 is fixed
    with SpooledTemporaryFile() as content_autoclose:

        # Write our original content into our copy that will be closed by boto3
        content_autoclose.write(content.read())

        # Upload the object which will auto close the
        # content_autoclose instance
        return super(CustomS3Boto3Storage, self)._save(name, content_autoclose)

记得在 settings.py 或您指定要使用的存储的任何其他地方更改它。

在我的例子中,我创建了一个名为 custom_s3_boto3_storage.py 的文件,因此:

DEFAULT_FILE_STORAGE = 'path.to.custom_s3_boto3_storage.CustomS3Boto3Storage'

解决方案来自https://github.com/matthewwithanm/django-imagekit/issues/391#issuecomment-592877289