Django `ImageFile.read()` raises `bytes object has no attribute read`

This is the model I’m using:

from django import models


class Image(models.Model):
    file = models.ImageField(upload_to='uploads/images/')

Now, if I do image.file.read() I get AttributeError: 'bytes' object has no attribute 'read'

>>> from images.models import Image
>>> img = Image.objects.first()
>>> img.file.read()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "...\.venv\lib\site-packages\django\core\files\utils.py", line 42, in <lambda>
    read = property(lambda self: self.file.read)
  File "...\.venv\lib\site-packages\django\core\files\utils.py", line 42, in <lambda>
    read = property(lambda self: self.file.read)
AttributeError: 'bytes' object has no attribute 'read'

image.file.file returns a bytes object and not a File object. I’m using Django 4.2.1 with python 3.10.7.

The following piece of code solves it, but is not a viable workaround.

import io

from images.models import Image


img = Image.objects.first()
img.file.file.file = io.BytesIO(img.file.file.file)

img.file.read() # Runs without errors

I believe that image.file.file.file should be a File object but it is returning a bytes object instead. Is there something I’m missing?

What is the raw value for that entry in the database? Normally it should only contain the file path string, which the storage engine needs to locate the file to do the file API stuff underneath. It seems that you somehow ended up providing the file’s byte directly into the database. How did you populate that file entry, is there any custom logic involved (custom storage engine, a custom script creating it by other means)?

The raw DB value is uploads/images/I2524DIFKRDKPHQ3W4AZY6WW2U.webp, the path to the file in my project’s storage. I’m using https://github.com/willmeyers/django-bunny-storage with an overriden url method.

from images.models import Image


img = Image.objects.first()

img.file # <ImageFile: uploads/images/I2524DIFKRDKPHQ3W4AZY6WW2U.webp>
img.file.file # <File: None>
img.file.file.file # b'\x...'

The records were created using both the admin site and a custom django-admin command. This happens with all models where there is an ImageField.

The project’s source code is in GitHub.

After checking my storage library’s code, I found that the error was in the library itself.

from django.core.file import File

import requests


class BunnyStorage(Storage):
    def _open(self, name, mode='rb'): 
        resp = requests.get(self.base_url + name, headers=self.headers)

        if resp.status_code == 404: 
            raise ValueError('File not found.')

        return File(resp.content)

After replacing File with io.BytesIO (which is a file-like object) the error stopped being raised.