summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetras Zdanavičius <petraszd@gmail.com>2014-07-26 15:25:44 +0300
committerTim Graham <timograham@gmail.com>2014-08-01 09:30:58 -0400
commit8b7347220f3d86b46f5f87270c6cdcb9960895fd (patch)
treee3068d20f882efd6b853fd64a538d601f088ba79
parent8c2b405ba8343e68bc32ac2c860be0c6cfd7d631 (diff)
Fixed #23103 -- Annotated ImageField file with image and content_type attributes.
Thanks Jeremy Dunck for the suggestion and Nick Sanford for review.
-rw-r--r--django/forms/fields.py7
-rw-r--r--docs/ref/forms/fields.txt9
-rw-r--r--docs/releases/1.8.txt6
-rw-r--r--tests/forms_tests/tests/filepath_test_files/1x1.pngbin0 -> 150 bytes
-rw-r--r--tests/forms_tests/tests/test_fields.py27
5 files changed, 47 insertions, 2 deletions
diff --git a/django/forms/fields.py b/django/forms/fields.py
index 9070963607..6e44ccfbb7 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -659,8 +659,13 @@ class ImageField(FileField):
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.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:
# Pillow doesn't recognize it as an image.
six.reraise(ValidationError, ValidationError(
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index a886536597..e92013a832 100644
--- a/docs/ref/forms/fields.txt
+++ b/docs/ref/forms/fields.txt
@@ -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
: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/
+.. _Image: https://pillow.readthedocs.org/en/latest/reference/Image.html
``IntegerField``
~~~~~~~~~~~~~~~~
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index d4943fd0da..15dca75e1d 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -160,6 +160,12 @@ Forms
: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.
+* 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
^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/forms_tests/tests/filepath_test_files/1x1.png b/tests/forms_tests/tests/filepath_test_files/1x1.png
new file mode 100644
index 0000000000..5e2f43a2e1
--- /dev/null
+++ b/tests/forms_tests/tests/filepath_test_files/1x1.png
Binary files differ
diff --git a/tests/forms_tests/tests/test_fields.py b/tests/forms_tests/tests/test_fields.py
index 2482fe0682..0b82b3940b 100644
--- a/tests/forms_tests/tests/test_fields.py
+++ b/tests/forms_tests/tests/test_fields.py
@@ -31,12 +31,18 @@ import pickle
import re
import os
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.forms import (
BooleanField, CharField, ChoiceField, ComboField, DateField, DateTimeField,
DecimalField, EmailField, Field, FileField, FilePathField, FloatField,
- Form, forms, HiddenInput, IntegerField, MultipleChoiceField,
+ Form, forms, HiddenInput, ImageField, IntegerField, MultipleChoiceField,
NullBooleanField, NumberInput, PasswordInput, RadioSelect, RegexField,
SplitDateTimeField, TextInput, Textarea, TimeField, TypedChoiceField,
TypedMultipleChoiceField, URLField, ValidationError, Widget,
@@ -741,6 +747,24 @@ class FieldsTests(SimpleTestCase):
# with here)
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 ##################################################################
def test_urlfield_1(self):
@@ -1262,6 +1286,7 @@ class FieldsTests(SimpleTestCase):
f.choices.sort()
expected = [
('/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/fake-image.jpg', 'fake-image.jpg'),
('/tests/forms_tests/tests/filepath_test_files/real-text-file.txt', 'real-text-file.txt'),