Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

python

django

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?

like image 753
Conan Avatar asked Jul 22 '11 04:07

Conan


2 Answers

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.

like image 107
shaunc Avatar answered Oct 19 '22 09:10

shaunc


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.

like image 22
Steven Oxley Avatar answered Oct 19 '22 11:10

Steven Oxley