Django“无法确定文件的大小”错误与tempfile.TemporaryFile

时间:2011-07-22 04:27:25

标签: python django

我遇到标准Django FileField和tempfile.TemporaryFile的问题。每当我尝试使用TemporaryFile保存FileField时,我都会收到“无法确定文件大小”的错误。

例如,给定名为Model的模型,名为FileField的文件字段和名为TempFile的临时文件:

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

这会给我上述错误。有什么想法吗?

5 个答案:

答案 0 :(得分:11)

tempfile.TemporaryFile我遇到了这个问题。当我切换到tempfile.NamedTemporaryFile时,它就消失了。我相信TemporaryFile只是模拟一个文件(至少在某些操作系统上),而NamedTemporaryFile实际上是一个文件。

答案 1 :(得分:2)

我遇到了同样的问题,能够为我的案子解决问题。这是django用来确定文件大小的代码:


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

因此,如果磁盘上不存在该文件(或者已经定义了size属性),则django将引发AttributeError。由于TemporaryFile类尝试在内存中创建文件而不是实际在磁盘上创建文件,因此此_get_size方法不起作用。为了让它发挥作用,我必须做这样的事情:


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)

或者(最好),如果您可以计算您正在创建的临时文件的大小,则可以直接在TemporaryFile对象上设置大小属性。由于我使用的库,这对我来说不可能。

答案 2 :(得分:2)

即使使用tempfile.NamedTemporaryFile,我在 Heroku 上也遇到了这个问题,并且非常失望......

我通过手动设置任意大小(是的,脏的,但对我有用)使用Steven的提示解决了它:

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))

谢谢!

答案 3 :(得分:0)

我知道这有点旧,但我已经通过使用 Django 提供的 ContentFile 类设法保存了一个 base64 文件(没有将实际文件保存在磁盘上)。

根据docs

<块引用>

ContentFile 类继承自 File,但与 File 不同的是,它操作的是字符串内容(也支持字节),而不是实际文件。

下面的代码段接收一个 base64 字符串,提取它的数据和文件扩展名,并使用 ImageField 类将其保存到 ContentFile

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']))

答案 4 :(得分:0)

在较新版本的 Django(我在 3.2 上检查过)中,您可能只需要将文件包装在 ContentFile 中。

from django.core.files.base import ContentFile

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

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