开发者

Django "Unable to determine the file's size" error with tempfile.TemporaryFile

I'm having problems with the standard开发者_开发技巧 Django FileField and tempfile.TemporaryFile. Whenever I try to save a FileField with the TemporaryFile, I get the "Unable to determine the file's size" error.

For example, given a model named Model, a filefield named FileField, and a temporaryfile named TempFile:

Model.FileField.save('foobar', django.core.files.File(TempFile), save=True)

This will give me the aforementioned error. Any thoughts?


I had this problem with tempfile.TemporaryFile. When I switched to tempfile.NamedTemporaryFile it went away. I believe that TemporaryFile just simulates being a file (on some operating system at least), whereas NamedTemporaryFile really is a file.


I was having the same problem and was able to solve it for my case. This is the code that django uses to determine the size of a file:


def _get_size(self):
  if not hasattr(self,  '_size'):
    if hasattr(self.file, 'size'):
      self._size = self.file.size
    elif os.path.exists(self.file.name):
      self._size = os.path.getsize(self.file.name)
    else:
      raise AttributeError("Unable to determine the file's size.")
  return self._size

Therefore, django will raise an AttributeError if the file does not exist on disk (or have a size attribute already defined). Since the TemporaryFile class attempts to create a file in memory instead of actually on disk, this _get_size method doesn't work. In order to get it to work, I had to do something like this:


import tempfile, os
# Use tempfile.mkstemp, since it will actually create the file on disk.
(temp_filedescriptor, temp_filepath) = tempfile.mkstemp()
# Close the open file using the file descriptor, since file objects
# returned by os.fdopen don't work, either
os.close(temp_filedescriptor)

# Open the file on disk
temp_file = open(temp_filepath, "w+b")

# Do operations on your file here . . .

modelObj.fileField.save("filename.txt", File(temp_file))

temp_file.close()
# Remove the created file from disk.
os.remove(temp_filepath)

Alternatively (and preferably), if you can calculate the size of the temporary file you're creating, you could set a size attribute on the TemporaryFile object directly. Due to the libraries I was using, this was not a possibility for me.


I had this issue on Heroku even with tempfile.NamedTemporaryFile and was quite disappointed ...

I solved it using Steven's tips by setting arbitrary size manually (yes, dirty, but work for me):

from django.core.files import File
from django.core.files.temp import NamedTemporaryFile

img_temp = NamedTemporaryFile()
# Do your stuffs ...
img_temp.flush()
img_temp.size = 1024

media.thumbnail.save('dummy', File(img_temp))

Thanks !


I know this is a bit old but I've managed to save a base64 file (without having the actual file saved on the disk) by using the ContentFile class provided by Django.

According to the docs:

The ContentFile class inherits from File, but unlike File it operates on string content (bytes also supported), rather than an actual file.

The snippet below receives a base64 string, extract it's data and file extension and save it to an ImageField using the ContentFile class

import uuid
from django.core.files.base import ContentFile


def convert_b64data(b64data, filename):
    file_format, imgstr = b64data.split(';base64,')
    ext = file_format.split('/')[-1]
    return {
        'obj': base64.b64decode(imgstr),
        'extension': ext,
    }


b64data = request.data['b64file']
filename = str(uuid.uuid4())
file_data = convert_b64data(b64data, filename)
file_path = 'media/{}/{}.{}'.format(
            user.code,
            filename,
            file_data['extension']
        )
user.banner.save(file_path, ContentFile(file_data['obj']))


In newer versions of Django (I checked on 3.2), you just may need to wrap the file in a ContentFile.

from django.core.files.base import ContentFile

Model.FileField.save('foobar', ContentFile(file))

https://docs.djangoproject.com/en/3.2/ref/files/file/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜