Loading django/core/validators.py +51 −0 Original line number Diff line number Diff line from __future__ import unicode_literals import os import re from django.core.exceptions import ValidationError Loading Loading @@ -452,3 +453,53 @@ class DecimalValidator(object): self.max_digits == other.max_digits and self.decimal_places == other.decimal_places ) @deconstructible class FileExtensionValidator(object): message = _( "File extension '%(extension)s' is not allowed. " "Allowed extensions are: '%(allowed_extensions)s'." ) code = 'invalid_extension' def __init__(self, allowed_extensions=None, message=None, code=None): self.allowed_extensions = allowed_extensions if message is not None: self.message = message if code is not None: self.code = code def __call__(self, value): extension = os.path.splitext(value.name)[1][1:].lower() if self.allowed_extensions is not None and extension not in self.allowed_extensions: raise ValidationError( self.message, code=self.code, params={ 'extension': extension, 'allowed_extensions': ', '.join(self.allowed_extensions) } ) def __eq__(self, other): return ( isinstance(other, self.__class__) and self.allowed_extensions == other.allowed_extensions and self.message == other.message and self.code == other.code ) def get_available_image_extensions(): try: from PIL import Image except ImportError: return [] else: Image.init() return [ext.lower()[1:] for ext in Image.EXTENSION.keys()] validate_image_file_extension = FileExtensionValidator( allowed_extensions=get_available_image_extensions(), ) django/db/models/fields/files.py +2 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ 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 import six Loading Loading @@ -378,6 +379,7 @@ class ImageFieldFile(ImageFile, FieldFile): class ImageField(FileField): default_validators = [validate_image_file_extension] attr_class = ImageFieldFile descriptor_class = ImageFileDescriptor description = _("Image") Loading docs/ref/validators.txt +27 −0 Original line number Diff line number Diff line Loading @@ -279,3 +279,30 @@ to, or in lieu of custom ``field.clean()`` methods. ``decimal_places``. - ``'max_whole_digits'`` if the number of whole digits is larger than the difference between ``max_digits`` and ``decimal_places``. ``FileExtensionValidator`` -------------------------- .. class:: FileExtensionValidator(allowed_extensions, message, code) .. versionadded:: 1.11 Raises a :exc:`~django.core.exceptions.ValidationError` with a code of ``'invalid_extension'`` if the ``value`` cannot be found in ``allowed_extensions``. .. warning:: Don't rely on validation of the file extension to determine a file's type. Files can be renamed to have any extension no matter what data they contain. ``validate_image_file_extension`` --------------------------------- .. data:: validate_image_file_extension .. versionadded:: 1.11 Uses Pillow to ensure that the ``value`` is `a valid image extension <https://pillow.readthedocs.org/en/latest/handbook/image-file-formats.html>`_. docs/releases/1.11.txt +7 −1 Original line number Diff line number Diff line Loading @@ -192,6 +192,9 @@ Models <django.db.models.query.QuerySet.update_or_create>` and :meth:`~django.db.models.query.QuerySet.get_or_create`. * :class:`~django.db.models.ImageField` now has a default :data:`~django.core.validators.validate_image_file_extension` validator. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ Loading Loading @@ -237,7 +240,10 @@ URLs Validators ~~~~~~~~~~ * ... * Added :class:`~django.core.validators.FileExtensionValidator` to validate file extensions and :data:`~django.core.validators.validate_image_file_extension` to validate image files. .. _backwards-incompatible-1.11: Loading tests/model_fields/test_imagefield.py +7 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import os import shutil from unittest import skipIf from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.files import File from django.core.files.images import ImageFile from django.test import TestCase Loading Loading @@ -133,6 +133,12 @@ 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 Loading Loading
django/core/validators.py +51 −0 Original line number Diff line number Diff line from __future__ import unicode_literals import os import re from django.core.exceptions import ValidationError Loading Loading @@ -452,3 +453,53 @@ class DecimalValidator(object): self.max_digits == other.max_digits and self.decimal_places == other.decimal_places ) @deconstructible class FileExtensionValidator(object): message = _( "File extension '%(extension)s' is not allowed. " "Allowed extensions are: '%(allowed_extensions)s'." ) code = 'invalid_extension' def __init__(self, allowed_extensions=None, message=None, code=None): self.allowed_extensions = allowed_extensions if message is not None: self.message = message if code is not None: self.code = code def __call__(self, value): extension = os.path.splitext(value.name)[1][1:].lower() if self.allowed_extensions is not None and extension not in self.allowed_extensions: raise ValidationError( self.message, code=self.code, params={ 'extension': extension, 'allowed_extensions': ', '.join(self.allowed_extensions) } ) def __eq__(self, other): return ( isinstance(other, self.__class__) and self.allowed_extensions == other.allowed_extensions and self.message == other.message and self.code == other.code ) def get_available_image_extensions(): try: from PIL import Image except ImportError: return [] else: Image.init() return [ext.lower()[1:] for ext in Image.EXTENSION.keys()] validate_image_file_extension = FileExtensionValidator( allowed_extensions=get_available_image_extensions(), )
django/db/models/fields/files.py +2 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ 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 import six Loading Loading @@ -378,6 +379,7 @@ class ImageFieldFile(ImageFile, FieldFile): class ImageField(FileField): default_validators = [validate_image_file_extension] attr_class = ImageFieldFile descriptor_class = ImageFileDescriptor description = _("Image") Loading
docs/ref/validators.txt +27 −0 Original line number Diff line number Diff line Loading @@ -279,3 +279,30 @@ to, or in lieu of custom ``field.clean()`` methods. ``decimal_places``. - ``'max_whole_digits'`` if the number of whole digits is larger than the difference between ``max_digits`` and ``decimal_places``. ``FileExtensionValidator`` -------------------------- .. class:: FileExtensionValidator(allowed_extensions, message, code) .. versionadded:: 1.11 Raises a :exc:`~django.core.exceptions.ValidationError` with a code of ``'invalid_extension'`` if the ``value`` cannot be found in ``allowed_extensions``. .. warning:: Don't rely on validation of the file extension to determine a file's type. Files can be renamed to have any extension no matter what data they contain. ``validate_image_file_extension`` --------------------------------- .. data:: validate_image_file_extension .. versionadded:: 1.11 Uses Pillow to ensure that the ``value`` is `a valid image extension <https://pillow.readthedocs.org/en/latest/handbook/image-file-formats.html>`_.
docs/releases/1.11.txt +7 −1 Original line number Diff line number Diff line Loading @@ -192,6 +192,9 @@ Models <django.db.models.query.QuerySet.update_or_create>` and :meth:`~django.db.models.query.QuerySet.get_or_create`. * :class:`~django.db.models.ImageField` now has a default :data:`~django.core.validators.validate_image_file_extension` validator. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ Loading Loading @@ -237,7 +240,10 @@ URLs Validators ~~~~~~~~~~ * ... * Added :class:`~django.core.validators.FileExtensionValidator` to validate file extensions and :data:`~django.core.validators.validate_image_file_extension` to validate image files. .. _backwards-incompatible-1.11: Loading
tests/model_fields/test_imagefield.py +7 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import os import shutil from unittest import skipIf from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.files import File from django.core.files.images import ImageFile from django.test import TestCase Loading Loading @@ -133,6 +133,12 @@ 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 Loading