Fixed #28242 -- Moved ImageField file extension validation to the form field.

This commit is contained in:
Manatsawin Hanmongkolchai 2017-05-28 14:05:21 +07:00 committed by Tim Graham
parent 6bb3b2bff4
commit a0c07d77fc
8 changed files with 47 additions and 11 deletions

View File

@ -6,7 +6,6 @@ from django.core import checks
from django.core.files.base import File
from django.core.files.images import ImageFile
from django.core.files.storage import default_storage
from django.core.validators import validate_image_file_extension
from django.db.models import signals
from django.db.models.fields import Field
from django.utils.translation import gettext_lazy as _
@ -355,7 +354,6 @@ class ImageFieldFile(ImageFile, FieldFile):
class ImageField(FileField):
default_validators = [validate_image_file_extension]
attr_class = ImageFieldFile
descriptor_class = ImageFileDescriptor
description = _("Image")

View File

@ -591,6 +591,7 @@ class FileField(Field):
class ImageField(FileField):
default_validators = [validators.validate_image_file_extension]
default_error_messages = {
'invalid_image': _(
"Upload a valid image. The file you uploaded was either not an "

View File

@ -58,3 +58,7 @@ Bugfixes
* Fixed a regression where ``file_move_safe()`` crashed when moving files to a
CIFS mount (:ticket:`28170`).
* Moved the ``ImageField`` file extension validation added in Django 1.11 from
the model field to the form field to reallow the use case of storing images
without an extension (:ticket:`28242`).

View File

@ -327,6 +327,7 @@ Models
* :class:`~django.db.models.ImageField` now has a default
:data:`~django.core.validators.validate_image_file_extension` validator.
(This validator moved to the form field in :doc:`Django 1.11.2 <1.11.2>`.)
* Added support for time truncation to
:class:`~django.db.models.functions.datetime.Trunc` functions.

View File

@ -2,7 +2,7 @@ import os
import unittest
from django.core.files.uploadedfile import SimpleUploadedFile
from django.forms import ImageField
from django.forms import ImageField, ValidationError
from django.test import SimpleTestCase
try:
@ -55,3 +55,12 @@ class ImageFieldTest(SimpleTestCase):
self.assertIsNone(uploaded_file.content_type)
finally:
Image.register_mime(BmpImageFile.format, 'image/bmp')
def test_file_extension_validation(self):
f = ImageField()
img_path = get_img_path('filepath_test_files/1x1.png')
with open(img_path, 'rb') as img_file:
img_data = img_file.read()
img_file = SimpleUploadedFile('1x1.txt', img_data)
with self.assertRaisesMessage(ValidationError, "File extension 'txt' is not allowed."):
f.clean(img_file)

View File

@ -2,7 +2,7 @@ import os
import shutil
from unittest import skipIf
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.exceptions import ImproperlyConfigured
from django.core.files import File
from django.core.files.images import ImageFile
from django.test import TestCase
@ -130,12 +130,6 @@ class ImageFieldTests(ImageFieldTestMixin, TestCase):
self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot))
self.assertIs(p1_db.mugshot != p1.mugshot, False)
def test_validation(self):
p = self.PersonModel(name="Joan")
p.mugshot.save("shot.txt", self.file1)
with self.assertRaisesMessage(ValidationError, "File extension 'txt' is not allowed."):
p.full_clean()
def test_instantiate_missing(self):
"""
If the underlying file is unavailable, still create instantiate the

View File

@ -192,6 +192,17 @@ try:
def __str__(self):
return self.description
class NoExtensionImageFile(models.Model):
def upload_to(self, filename):
return 'tests/no_extension'
description = models.CharField(max_length=20)
image = models.ImageField(storage=temp_storage, upload_to=upload_to)
def __str__(self):
return self.description
except ImportError:
test_images = False

View File

@ -32,7 +32,7 @@ from .models import (
)
if test_images:
from .models import ImageFile, OptionalImageFile
from .models import ImageFile, OptionalImageFile, NoExtensionImageFile
class ImageFileForm(forms.ModelForm):
class Meta:
@ -44,6 +44,11 @@ if test_images:
model = OptionalImageFile
fields = '__all__'
class NoExtensionImageFileForm(forms.ModelForm):
class Meta:
model = NoExtensionImageFile
fields = '__all__'
class ProductForm(forms.ModelForm):
class Meta:
@ -2461,6 +2466,19 @@ class FileAndImageFieldTests(TestCase):
self.assertEqual(instance.image.name, 'foo/test4.png')
instance.delete()
# Editing an instance that has an image without an extension shouldn't
# fail validation. First create:
f = NoExtensionImageFileForm(
data={'description': 'An image'},
files={'image': SimpleUploadedFile('test.png', image_data)},
)
self.assertTrue(f.is_valid())
instance = f.save()
self.assertEqual(instance.image.name, 'tests/no_extension')
# Then edit:
f = NoExtensionImageFileForm(data={'description': 'Edited image'}, instance=instance)
self.assertTrue(f.is_valid())
class ModelOtherFieldTests(SimpleTestCase):
def test_big_integer_field(self):