[Django]-I/O operation on closed file in django with 'ImageKit'

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

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

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

Leave a comment