为什么Django的ImageField没有在这里抛出一个验证错误?
# field in model
image_mobile = ImageField(
upload_to='static/images/',
blank=True,
null=True
)
# in test
from django.core.files.uploadedfile import SimpleUploadedFile
attachment = SimpleUploadedFile("file.mp4", b"file_content", content_type="text/plain")
obj.image_mobile = attachment
obj.save()
self.assertEqual(obj.image_mobile, '')产出如下:
AssertionError: <ImageFieldFile: static/images/file_7wanB5P.mp4> != ''从文件中:
从FileField继承所有属性和方法,但也验证上载的对象是有效的图像。
发布于 2019-08-07 08:39:57
看来是PIL图书馆的事了。Django使用它获取图像维度,这似乎是ImageField的唯一验证。它获取文件的前1024字节并读取元数据,而且很可能mp4和jpeg有类似的数据。所以这不是最可靠的检查方法
try:
# Most of the time Pillow only needs a small chunk to parse the image
# and get the dimensions, but with some TIFF files Pillow needs to
# parse the whole file.
chunk_size = 1024
while 1:
data = file.read(chunk_size)
if not data:
break
try:
p.feed(data)
except zlib.error as e:
# ignore zlib complaining on truncated stream, just feed more
# data to parser (ticket #19457).
if e.args[0].startswith("Error -5"):
pass
else:
raise
except struct.error:
# Ignore PIL failing on a too short buffer when reads return
# less bytes than expected. Skip and feed more data to the
# parser (ticket #24544).
pass
except RuntimeError:
# e.g. "RuntimeError: could not create decoder object" for
# WebP files. A different chunk_size may work.
pass
if p.image:
return p.image.size
chunk_size *= 2
return (None, None)
finally:
if close:
file.close()
else:
file.seek(file_pos)发布于 2019-08-13 04:26:36
def to_python(self, data):
"""
Check that the file-upload field data contains a valid image (GIF, JPG,
PNG, etc. -- whatever Pillow supports).
"""
f = super().to_python(data)
if f is None:
return None
from PIL import Image
# 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'])
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.
image.verify()
# 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)
except Exception as exc:
# Pillow doesn't recognize it as an image.
raise ValidationError(
self.error_messages['invalid_image'],
code='invalid_image',
) from exc
if hasattr(f, 'seek') and callable(f.seek):
f.seek(0)
return f这是运行的代码,如果您看到文档
https://pillow.readthedocs.io/en/5.1.x/reference/Image.html?highlight=verify#PIL.Image.Image.verify
Image.verify() 验证文件的内容。对于从文件中读取的数据,此方法尝试确定文件是否已损坏,而不实际解码图像数据。如果此方法发现任何问题,则会引发适当的异常。如果需要在使用此方法后加载图像,则必须重新打开图像文件。
因此,基本上它是试图确定该文件是否已损坏。而且可能是它正在验证您的mp4文件,这就是为什么没有例外。如果需要更严格的验证,则需要使用magic或其他库来确定文件类型。如下所示,线程相同
How does one use magic to verify file type in a Django form clean method?
Django: file field validation in model using python-magic
Django: Validate file type of uploaded file
https://timmyomahony.com/blog/upload-and-validate-image-from-url-in-django/
https://stackoverflow.com/questions/57389724
复制相似问题