3

In my django project I am using ImageKit to size my profile images.

I have a model with these fields:

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

ImageSpecField is imported from Imagekit.

I am saving my images on amazon-S3 via Django-storages

When I upload an image via the template (edit form) rendered via an UpdateView it shows the detail template after success. The pasfoto_thumbnail is used in this template, that is rendered via a class based DetailView in Django.

In this case I see an error 'I/O operation on closed file'. But after a browser refresh is shows the right image. What is happening and how could I solve this issue?


Django Debug page/info for this error

MDekker
  • 443
  • 1
  • 4
  • 19

3 Answers3

5

I recently had the same issue and it was preventing me to upgrade django-storages to the latest version.

I finally tracked down the issue to this old django-storages issue.

And in that thread they mention django s3 storages. Migrating to that library seems to fix it.

pssuils
  • 76
  • 1
  • 5
1

I had this issue with my old project and Django 2. I discovered it happens with some old versions of packages. What helped in my case was to upgrade django and pillow according to alerts I got from github dependabot.

I run pipenv install django=='2.2.24' pillow=='8.3.2' and the issue was gone for me.

ann.piv
  • 681
  • 1
  • 7
  • 17
0

I'm using Django==3.2.13, django-storages==1.12.3, Pillow==9.1.1 and django-imagekit==4.1.0 and had to overwrite the default storage like this:

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)

Remember to change it in settings.py or in any other place where you specify which storage to use.

In my case I created a file named custom_s3_boto3_storage.py so:

DEFAULT_FILE_STORAGE = 'path.to.custom_s3_boto3_storage.CustomS3Boto3Storage'

The solution is from https://github.com/matthewwithanm/django-imagekit/issues/391#issuecomment-592877289

Martin
  • 660
  • 10
  • 23