为什么form中的ImageField总是触发"invalid_image"?

Why ImageField in form always triggers "invalid_image"?

我在 Django 1.8 中使用 Pillow 验证实现了 ImageField 上传图片。由于某种原因,我无法提交表格。它总是在表单中引发此 ValidationError(但使用 FileField 这会起作用):

Upload a valid image. The file you uploaded was either not an image or a corrupted image.

所有这一切的奇怪之处在于 ImageField.check 方法似乎获得了正确的 MIME 类型! (见下文)

我尝试了什么

我试过 JPG、GIF 和 PNG 格式; none 成功了。

所以我尝试在django.forms.fields.ImageField中打印一些变量修改触发此错误的try语句,添加打印语句进行测试:

try:
    # load() could spot a truncated JPEG, but it loads the entire
    # image in memory, which is a DoS vector. See #3848 and #18520.
    image = Image.open(file)
    # verify() must be called immediately after the constructor.
    damnit = image.verify()
    print 'MY_LOG: verif=', damnit

    # Annotating so subclasses can reuse it for their own validation
    f.image = image
    # Pillow doesn't detect the MIME type of all formats. In those
    # cases, content_type will be None.
    f.content_type = Image.MIME.get(image.format)
    print 'MY_LOG: image_format=', image.format
    print 'MY_LOG: content_type=', f.content_type

然后我再次提交表单以在运行 python manage.py runserver 之后触发错误并获得这些行:

MY_LOG: verif= None

MY_LOG: image_format= JPEG

MY_LOG: content_type= image/jpeg

图像被 Pillow 正确识别并且 try 语句一直执行到最后一行...但仍然触发了 except 语句?胡说八道!

使用相同的策略,我尝试从 django.db.models.fields.files.ImageField 和它的每个父级获取一些有用的日志,直到 Field 打印错误列表...它们都是空的!

我的问题

还有什么我可以尝试找出触发 ValidationError 的原因吗?

一些代码

models.py

class MyImageModel(models.Model):
    # Using FileField instead would mean succesfull upload
    the_image = models.ImageField(upload_to="public_uploads/", blank=True, null=True)

views.py

from django.views.generic.edit import CreateView
from django.forms.models import modelform_factory

class MyFormView(CreateView):
    model = MyImageModel
    form_class = modelform_factory(MyImageModel,
                 widgets={}, fields = ['the_image',])

编辑:

在尝试了@Alasdair 建议的策略后,我从 e.message 获得了这份报告:

cannot identify image file <_io.BytesIO object at 0x7f9d52bbc770>

但是,即使不允许我提交表单,文件也已成功上传。看起来是否以某种方式未正确处理图像路径(或其他阻碍图像在这些行中加载的东西)。

我认为这些方面可能有问题(来自 django.forms.fields.ImageField):

# We need to get a file object for Pillow. We might have a path or we might
# have to read the data into memory.
if hasattr(data, 'temporary_file_path'):
    file = data.temporary_file_path()
else:
    if hasattr(data, 'read'):
        file = BytesIO(data.read())
else:
    file = BytesIO(data['content'])

如果我探索这个 class BytesIO 有什么属性,也许我可以提取一些关于错误的相关信息...

编辑2

data属性空空如也!确定原因并不容易...

来自 django 文档:

Using an ImageField requires that Pillow is installed with support for the image formats you use. If you encounter a corrupt image error when you upload an image, it usually means that Pillow doesn’t understand its format. To fix this, install the appropriate library and reinstall Pillow.

因此,首先,您应该安装 Pillow,而不是 PIL(pillow 是 PIL 的一个分支),其次,在安装时,确保安装 Pillow 各种图像格式 "understanding" 所需的所有库.

有关依赖项列表,您可以查看 Pillow 文档。

经过深思熟虑、分析隐含代码和大量反复试验后,我尝试从我在问题中公开的 try / except 块编辑这一行(在 django.forms.fields.ImageField ) 像这样:

# Before edition
image = Image.open(file)

# After my edition
image = Image.open(f)

这解决了我的问题。现在一切正常,我可以提交表格了。无效文件被相应的 ValidationError

正确拒绝

我猜这怎么会发生

我不确定我是否猜对了,但是:

I think this worked because this line had an error naming the correct variable. In addition, using file as a variable name looks like a typo, because file seems to be reserved for an existing built-in.

如果我的猜测是正确的,也许我应该向 Django 开发人员报告这个问题