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/
精彩评论