为什么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 开发人员报告这个问题
我在 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 acorrupt 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, becausefile
seems to be reserved for an existing built-in.
如果我的猜测是正确的,也许我应该向 Django 开发人员报告这个问题