Fixed #23103 -- Annotated ImageField file with image and content_type attributes.
Thanks Jeremy Dunck for the suggestion and Nick Sanford for review.
This commit is contained in:
parent
8c2b405ba8
commit
8b7347220f
|
@ -659,8 +659,13 @@ class ImageField(FileField):
|
||||||
try:
|
try:
|
||||||
# load() could spot a truncated JPEG, but it loads the entire
|
# load() could spot a truncated JPEG, but it loads the entire
|
||||||
# image in memory, which is a DoS vector. See #3848 and #18520.
|
# image in memory, which is a DoS vector. See #3848 and #18520.
|
||||||
|
image = Image.open(file)
|
||||||
# verify() must be called immediately after the constructor.
|
# verify() must be called immediately after the constructor.
|
||||||
Image.open(file).verify()
|
image.verify()
|
||||||
|
|
||||||
|
# Annotating so subclasses can reuse it for their own validation
|
||||||
|
f.image = image
|
||||||
|
f.content_type = Image.MIME[image.format]
|
||||||
except Exception:
|
except Exception:
|
||||||
# Pillow doesn't recognize it as an image.
|
# Pillow doesn't recognize it as an image.
|
||||||
six.reraise(ValidationError, ValidationError(
|
six.reraise(ValidationError, ValidationError(
|
||||||
|
|
|
@ -649,7 +649,16 @@ For each field, we describe the default widget used if you don't specify
|
||||||
When you use an ``ImageField`` on a form, you must also remember to
|
When you use an ``ImageField`` on a form, you must also remember to
|
||||||
:ref:`bind the file data to the form <binding-uploaded-files>`.
|
:ref:`bind the file data to the form <binding-uploaded-files>`.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.8
|
||||||
|
|
||||||
|
After the field has been cleaned and validated, the ``UploadedFile``
|
||||||
|
object will have an additional ``image`` attribute containing the Pillow
|
||||||
|
`Image`_ instance used to check if the file was a valid image.
|
||||||
|
``UploadedFile.content_type`` is also updated with the image's content
|
||||||
|
type as determined by Pillow.
|
||||||
|
|
||||||
.. _Pillow: http://pillow.readthedocs.org/en/latest/
|
.. _Pillow: http://pillow.readthedocs.org/en/latest/
|
||||||
|
.. _Image: https://pillow.readthedocs.org/en/latest/reference/Image.html
|
||||||
|
|
||||||
``IntegerField``
|
``IntegerField``
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -160,6 +160,12 @@ Forms
|
||||||
:attr:`~django.forms.extras.widgets.SelectDateWidget.empty_label` argument, which will
|
:attr:`~django.forms.extras.widgets.SelectDateWidget.empty_label` argument, which will
|
||||||
override the top list choice label when :class:`~django.forms.DateField` is not required.
|
override the top list choice label when :class:`~django.forms.DateField` is not required.
|
||||||
|
|
||||||
|
* After an :class:`~django.forms.ImageField` has been cleaned and validated, the
|
||||||
|
``UploadedFile`` object will have an additional ``image`` attribute containing
|
||||||
|
the Pillow ``Image`` instance used to check if the file was a valid image. It
|
||||||
|
will also update ``UploadedFile.content_type`` with the image's content type
|
||||||
|
as determined by Pillow.
|
||||||
|
|
||||||
Internationalization
|
Internationalization
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 150 B |
|
@ -31,12 +31,18 @@ import pickle
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from unittest import skipIf
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PIL import Image
|
||||||
|
except ImportError:
|
||||||
|
Image = None
|
||||||
|
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.forms import (
|
from django.forms import (
|
||||||
BooleanField, CharField, ChoiceField, ComboField, DateField, DateTimeField,
|
BooleanField, CharField, ChoiceField, ComboField, DateField, DateTimeField,
|
||||||
DecimalField, EmailField, Field, FileField, FilePathField, FloatField,
|
DecimalField, EmailField, Field, FileField, FilePathField, FloatField,
|
||||||
Form, forms, HiddenInput, IntegerField, MultipleChoiceField,
|
Form, forms, HiddenInput, ImageField, IntegerField, MultipleChoiceField,
|
||||||
NullBooleanField, NumberInput, PasswordInput, RadioSelect, RegexField,
|
NullBooleanField, NumberInput, PasswordInput, RadioSelect, RegexField,
|
||||||
SplitDateTimeField, TextInput, Textarea, TimeField, TypedChoiceField,
|
SplitDateTimeField, TextInput, Textarea, TimeField, TypedChoiceField,
|
||||||
TypedMultipleChoiceField, URLField, ValidationError, Widget,
|
TypedMultipleChoiceField, URLField, ValidationError, Widget,
|
||||||
|
@ -741,6 +747,24 @@ class FieldsTests(SimpleTestCase):
|
||||||
# with here)
|
# with here)
|
||||||
self.assertTrue(f._has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'}))
|
self.assertTrue(f._has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'}))
|
||||||
|
|
||||||
|
# ImageField ##################################################################
|
||||||
|
|
||||||
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
|
def test_imagefield_annotate_with_image_after_clean(self):
|
||||||
|
f = ImageField()
|
||||||
|
|
||||||
|
img_path = os.path.dirname(upath(__file__)) + '/filepath_test_files/1x1.png'
|
||||||
|
with open(img_path, 'rb') as img_file:
|
||||||
|
img_data = img_file.read()
|
||||||
|
|
||||||
|
img_file = SimpleUploadedFile('1x1.png', img_data)
|
||||||
|
img_file.content_type = 'text/plain'
|
||||||
|
|
||||||
|
uploaded_file = f.clean(img_file)
|
||||||
|
|
||||||
|
self.assertEqual('PNG', uploaded_file.image.format)
|
||||||
|
self.assertEqual('image/png', uploaded_file.content_type)
|
||||||
|
|
||||||
# URLField ##################################################################
|
# URLField ##################################################################
|
||||||
|
|
||||||
def test_urlfield_1(self):
|
def test_urlfield_1(self):
|
||||||
|
@ -1262,6 +1286,7 @@ class FieldsTests(SimpleTestCase):
|
||||||
f.choices.sort()
|
f.choices.sort()
|
||||||
expected = [
|
expected = [
|
||||||
('/tests/forms_tests/tests/filepath_test_files/.dot-file', '.dot-file'),
|
('/tests/forms_tests/tests/filepath_test_files/.dot-file', '.dot-file'),
|
||||||
|
('/tests/forms_tests/tests/filepath_test_files/1x1.png', '1x1.png'),
|
||||||
('/tests/forms_tests/tests/filepath_test_files/directory', 'directory'),
|
('/tests/forms_tests/tests/filepath_test_files/directory', 'directory'),
|
||||||
('/tests/forms_tests/tests/filepath_test_files/fake-image.jpg', 'fake-image.jpg'),
|
('/tests/forms_tests/tests/filepath_test_files/fake-image.jpg', 'fake-image.jpg'),
|
||||||
('/tests/forms_tests/tests/filepath_test_files/real-text-file.txt', 'real-text-file.txt'),
|
('/tests/forms_tests/tests/filepath_test_files/real-text-file.txt', 'real-text-file.txt'),
|
||||||
|
|
Loading…
Reference in New Issue