Skip to content

Instantly share code, notes, and snippets.

@mobula
Forked from jrosebr1/validators.py
Last active April 7, 2019 21:52

Revisions

  1. mobula revised this gist Nov 4, 2014. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -63,6 +63,14 @@ def __init__(self, *args, **kwargs):
    self.min_size = kwargs.pop('min_size', 0)
    self.max_size = kwargs.pop('max_size', None)

    def __eq__(self, other):
    return ( isinstance(other, FileValidator)
    and (self.allowed_extensions == other.allowed_extensions)
    and (self.allowed_mimetypes == other.allowed_mimetypes)
    and (self.min_size == other.min_size)
    and (self.max_size == other.max_size)
    )

    def __call__(self, value):
    """
    Check the extension, content type and file size.
    @@ -151,6 +159,15 @@ def __init__(self, *args, **kwargs):
    self.min_size = kwargs.pop('min_size', 0)
    self.max_size = kwargs.pop('max_size', None)

    def __eq__(self, other):
    return ( isinstance(other, ImageValidator)
    and (self.allowed_formats == other.allowed_formats)
    and (self.allowed_extensions == other.allowed_extensions)
    and (self.allowed_mimetypes == other.allowed_mimetypes)
    and (self.min_size == other.min_size)
    and (self.max_size == other.max_size)
    )

    def __call__(self, value):
    """
    Check the extension, content type and file size.
  2. mobula revised this gist Oct 29, 2014. 1 changed file with 138 additions and 0 deletions.
    138 changes: 138 additions & 0 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,10 @@
    # Performs file upload validation for django.
    # with Django 1.7 migrations support (deconstructible)

    # Provides:
    # - FileValidator
    # - ImageValidator (adds Image specific validation using PIL)

    # @author dokterbob
    # @author jrosebr1
    # @author mobula
    @@ -105,3 +109,137 @@ def __call__(self, value):
    'allowed_size': filesizeformat(self.min_size)
    }
    raise ValidationError(message=message, code=code, params=params)


    @deconstructible
    class ImageValidator(object):
    """
    Validator for images, using PIL
    Initialization parameters:
    allowed_extensions: iterable with allowed file extensions
    ie. ('jpg', 'jpeg', 'gif, 'png', 'tiff', 'bmp')
    allowed_formats: iterable with allowed file types
    ie. ('jpeg', 'gif', 'png')
    allowed_mimetypes: iterable with allowed mimetypes
    ie. ('image/png')
    min_size: minimum number of bytes allowed
    ie. 100
    max_size: maximum number of bytes allowed
    ie. 24*1024*1024 for 24 MB
    Usage example::
    MyModel(models.Model):
    myfile = ImageField(validators=ImageValidator(max_size=24*1024*1024), ...)
    """
    messages = {
    'not_an_image': _("File is not a recognized image '%(file)s'."),
    'broken_image': _("The uploaded image seems to be broken '%(file)s'."),
    'format_mismatch': _("Extension name '%(extension)s' doesn't match actual file format '%(format)s'."),
    'format_not_allowed': _("Extension '%(format)s' not allowed. Allowed extensions are: '%(allowed_formats)s.'"),
    'extension_not_allowed': _("Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'"),
    'mimetype_not_allowed': _("MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s."),
    'min_size': _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s.'),
    'max_size': _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s.')
    }

    def __init__(self, *args, **kwargs):
    self.allowed_formats = kwargs.pop('allowed_formats', None)
    self.allowed_extensions = kwargs.pop('allowed_extensions', None)
    self.allowed_mimetypes = kwargs.pop('allowed_mimetypes', None)
    self.min_size = kwargs.pop('min_size', 0)
    self.max_size = kwargs.pop('max_size', None)

    def __call__(self, value):
    """
    Check the extension, content type and file size.
    """
    from PIL import Image
    # from __future__ import print_function

    try:
    im = Image.open(value)
    except:
    code = 'not_an_image'
    message = self.messages[code]
    params = {
    'file': value,
    }
    raise ValidationError(message=message, code=code, params=params)

    try:
    im.verify()
    except:
    code = 'broken_image'
    message = self.messages[code]
    params = {
    'file': value,
    }
    raise ValidationError(message=message, code=code, params=params)

    # Check the format
    format = im.format.lower()
    if self.allowed_formats and not format in self.allowed_formats:
    code = 'format_not_allowd'
    message = self.messages[code]
    params = {
    'format' : ext,
    'allowed_formats': ', '.join(self.allowed_formats)
    }
    raise ValidationError(message=message, code=code, params=params)

    # Check the extension
    ext = splitext(value.name)[1][1:].lower()
    if self.allowed_extensions and not ext in self.allowed_extensions:
    code = 'extension_not_allowed'
    message = self.messages[code]
    params = {
    'extension' : ext,
    'allowed_extensions': ', '.join(self.allowed_extensions)
    }
    raise ValidationError(message=message, code=code, params=params)

    # Check extension and file format consistency
    if ext == 'jpg':
    ext = 'jpeg'
    if format != ext:
    code = 'format_mismatch'
    message = self.messages[code]
    params = {
    'extension' : ext,
    'format': format
    }
    raise ValidationError(message=message, code=code, params=params)

    # Check the content type
    mimetype = mimetypes.guess_type(value.name)[0]
    if self.allowed_mimetypes and not mimetype in self.allowed_mimetypes:
    code = 'mimetype_not_allowed'
    message = self.messages[code]
    params = {
    'mimetype': mimetype,
    'allowed_mimetypes': ', '.join(self.allowed_mimetypes)
    }
    raise ValidationError(message=message, code=code, params=params)

    # Check the file size
    filesize = len(value)
    if self.max_size and filesize > self.max_size:
    code = 'max_size'
    message = self.messages[code]
    params = {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.max_size)
    }
    raise ValidationError(message=message, code=code, params=params)

    elif filesize < self.min_size:
    code = 'min_size'
    message = self.messages[code]
    params = {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.min_size)
    }
    raise ValidationError(message=message, code=code, params=params)

  3. mobula revised this gist Oct 29, 2014. 1 changed file with 34 additions and 18 deletions.
    52 changes: 34 additions & 18 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,13 @@
    # -*- coding: utf-8 -*-
    # https://gist.github.com/mobula/da99e4db843b9ceb3a3f

    # @brief
    # Performs file upload validation for django. The original version implemented
    # by dokterbob had some problems with determining the correct mimetype and
    # determining the size of the file uploaded (at least within my Django application
    # that is).
    # Performs file upload validation for django.
    # with Django 1.7 migrations support (deconstructible)

    # @author dokterbob
    # @author jrosebr1
    # @author mobula

    import mimetypes
    from os.path import splitext
    @@ -14,15 +16,19 @@
    from django.utils.translation import ugettext_lazy as _
    from django.template.defaultfilters import filesizeformat

    from django.utils.deconstruct import deconstructible



    @deconstructible
    class FileValidator(object):
    """
    Validator for files, checking the size, extension and mimetype.
    Initialization parameters:
    allowed_extensions: iterable with allowed file extensions
    ie. ('txt', 'doc')
    allowd_mimetypes: iterable with allowed mimetypes
    allowed_mimetypes: iterable with allowed mimetypes
    ie. ('image/png', )
    min_size: minimum number of bytes allowed
    ie. 100
    @@ -36,7 +42,13 @@ class FileValidator(object):
    """

    extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'")
    messages = {
    'extension_not_allowed': _("Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'"),
    'mimetype_not_allowed': _("MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s."),
    'min_size': _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s.'),
    'max_size': _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s.')
    }

    mime_message = _("MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s.")
    min_size_message = _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s.')
    max_size_message = _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s.')
    @@ -55,37 +67,41 @@ def __call__(self, value):
    # Check the extension
    ext = splitext(value.name)[1][1:].lower()
    if self.allowed_extensions and not ext in self.allowed_extensions:
    message = self.extension_message % {
    code = 'extension_not_allowed'
    message = self.messages[code]
    params = {
    'extension' : ext,
    'allowed_extensions': ', '.join(self.allowed_extensions)
    }

    raise ValidationError(message)
    raise ValidationError(message=message, code=code, params=params)

    # Check the content type
    mimetype = mimetypes.guess_type(value.name)[0]
    if self.allowed_mimetypes and not mimetype in self.allowed_mimetypes:
    message = self.mime_message % {
    code = 'mimetype_not_allowed'
    message = self.messages[code]
    params = {
    'mimetype': mimetype,
    'allowed_mimetypes': ', '.join(self.allowed_mimetypes)
    }

    raise ValidationError(message)
    raise ValidationError(message=message, code=code, params=params)

    # Check the file size
    filesize = len(value)
    if self.max_size and filesize > self.max_size:
    message = self.max_size_message % {
    code = 'max_size'
    message = self.messages[code]
    params = {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.max_size)
    }

    raise ValidationError(message)
    raise ValidationError(message=message, code=code, params=params)

    elif filesize < self.min_size:
    message = self.min_size_message % {
    code = 'min_size'
    message = self.messages[code]
    params = {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.min_size)
    }

    raise ValidationError(message)
    raise ValidationError(message=message, code=code, params=params)
  4. @jrosebr1 jrosebr1 revised this gist Mar 20, 2012. 1 changed file with 14 additions and 3 deletions.
    17 changes: 14 additions & 3 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,13 @@
    # @brief
    # Performs file upload validation for django. The original version implemented
    # by dokterbob had some problems with determining the correct mimetype and
    # determining the size of the file uploaded (at least within my Django application
    # that is).

    # @author dokterbob
    # @author jrosebr1

    import mimetypes
    from os.path import splitext

    from django.core.exceptions import ValidationError
    @@ -41,6 +51,7 @@ def __call__(self, value):
    """
    Check the extension, content type and file size.
    """

    # Check the extension
    ext = splitext(value.name)[1][1:].lower()
    if self.allowed_extensions and not ext in self.allowed_extensions:
    @@ -52,7 +63,7 @@ def __call__(self, value):
    raise ValidationError(message)

    # Check the content type
    mimetype = value.file.content_type
    mimetype = mimetypes.guess_type(value.name)[0]
    if self.allowed_mimetypes and not mimetype in self.allowed_mimetypes:
    message = self.mime_message % {
    'mimetype': mimetype,
    @@ -62,7 +73,7 @@ def __call__(self, value):
    raise ValidationError(message)

    # Check the file size
    filesize = value.file._size
    filesize = len(value)
    if self.max_size and filesize > self.max_size:
    message = self.max_size_message % {
    'size': filesizeformat(filesize),
    @@ -77,4 +88,4 @@ def __call__(self, value):
    'allowed_size': filesizeformat(self.min_size)
    }

    raise ValidationError(message)
    raise ValidationError(message)
  5. Mathijs de Bruin revised this gist Aug 31, 2011. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -26,10 +26,10 @@ class FileValidator(object):
    """

    extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions: '%(allowed_extensions)s'")
    mime_message = _("MIME type '%(mimetype)s' is not valid. Allowed types: %(allowed_mimetypes)s")
    min_size_message = _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s')
    max_size_message = _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s')
    extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'")
    mime_message = _("MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s.")
    min_size_message = _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s.')
    max_size_message = _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s.')

    def __init__(self, *args, **kwargs):
    self.allowed_extensions = kwargs.pop('allowed_extensions', None)
  6. Mathijs de Bruin revised this gist Aug 31, 2011. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -19,6 +19,11 @@ class FileValidator(object):
    max_size: maximum number of bytes allowed
    ie. 24*1024*1024 for 24 MB
    Usage example::
    MyModel(models.Model):
    myfile = FileField(validators=FileValidator(max_size=24*1024*1024), ...)
    """

    extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions: '%(allowed_extensions)s'")
  7. Mathijs de Bruin revised this gist Aug 31, 2011. 1 changed file with 3 additions and 5 deletions.
    8 changes: 3 additions & 5 deletions validators.py
    Original file line number Diff line number Diff line change
    @@ -2,14 +2,12 @@

    from django.core.exceptions import ValidationError
    from django.utils.translation import ugettext_lazy as _
    from django.forms.fields import FileField
    from django.template.defaultfilters import filesizeformat


    class FileValidator(object):
    """
    Subclass of the FileField form field which optionally checks the
    extension, mimetype and size of the uploaded files.
    Validator for files, checking the size, extension and mimetype.
    Initialization parameters:
    allowed_extensions: iterable with allowed file extensions
    @@ -39,7 +37,7 @@ def __call__(self, value):
    Check the extension, content type and file size.
    """
    # Check the extension
    ext = splitext(value)[1][1:].lower()
    ext = splitext(value.name)[1][1:].lower()
    if self.allowed_extensions and not ext in self.allowed_extensions:
    message = self.extension_message % {
    'extension' : ext,
    @@ -60,7 +58,7 @@ def __call__(self, value):

    # Check the file size
    filesize = value.file._size
    if filesize > self.max_size:
    if self.max_size and filesize > self.max_size:
    message = self.max_size_message % {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.max_size)
  8. Mathijs de Bruin renamed this gist Aug 31, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  9. Mathijs de Bruin revised this gist Aug 31, 2011. 1 changed file with 2 additions and 8 deletions.
    10 changes: 2 additions & 8 deletions snippet.sc
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ from django.forms.fields import FileField
    from django.template.defaultfilters import filesizeformat


    class ValidatingFileField(FileField):
    class FileValidator(object):
    """
    Subclass of the FileField form field which optionally checks the
    extension, mimetype and size of the uploaded files.
    @@ -34,14 +34,10 @@ class ValidatingFileField(FileField):
    self.min_size = kwargs.pop('min_size', 0)
    self.max_size = kwargs.pop('max_size', None)

    super(ValidatingFileField, self).__init__(*args, **kwargs)

    def clean(self, value):
    def __call__(self, value):
    """
    Check the extension, content type and file size.
    """
    value = super(ValidatingFileField, self).clean(value)

    # Check the extension
    ext = splitext(value)[1][1:].lower()
    if self.allowed_extensions and not ext in self.allowed_extensions:
    @@ -79,5 +75,3 @@ class ValidatingFileField(FileField):
    }

    raise ValidationError(message)

    return value
  10. Mathijs de Bruin created this gist Aug 31, 2011.
    83 changes: 83 additions & 0 deletions snippet.sc
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,83 @@
    from os.path import splitext

    from django.core.exceptions import ValidationError
    from django.utils.translation import ugettext_lazy as _
    from django.forms.fields import FileField
    from django.template.defaultfilters import filesizeformat


    class ValidatingFileField(FileField):
    """
    Subclass of the FileField form field which optionally checks the
    extension, mimetype and size of the uploaded files.
    Initialization parameters:
    allowed_extensions: iterable with allowed file extensions
    ie. ('txt', 'doc')
    allowd_mimetypes: iterable with allowed mimetypes
    ie. ('image/png', )
    min_size: minimum number of bytes allowed
    ie. 100
    max_size: maximum number of bytes allowed
    ie. 24*1024*1024 for 24 MB
    """

    extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions: '%(allowed_extensions)s'")
    mime_message = _("MIME type '%(mimetype)s' is not valid. Allowed types: %(allowed_mimetypes)s")
    min_size_message = _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s')
    max_size_message = _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s')

    def __init__(self, *args, **kwargs):
    self.allowed_extensions = kwargs.pop('allowed_extensions', None)
    self.allowed_mimetypes = kwargs.pop('allowed_mimetypes', None)
    self.min_size = kwargs.pop('min_size', 0)
    self.max_size = kwargs.pop('max_size', None)

    super(ValidatingFileField, self).__init__(*args, **kwargs)

    def clean(self, value):
    """
    Check the extension, content type and file size.
    """
    value = super(ValidatingFileField, self).clean(value)

    # Check the extension
    ext = splitext(value)[1][1:].lower()
    if self.allowed_extensions and not ext in self.allowed_extensions:
    message = self.extension_message % {
    'extension' : ext,
    'allowed_extensions': ', '.join(self.allowed_extensions)
    }

    raise ValidationError(message)

    # Check the content type
    mimetype = value.file.content_type
    if self.allowed_mimetypes and not mimetype in self.allowed_mimetypes:
    message = self.mime_message % {
    'mimetype': mimetype,
    'allowed_mimetypes': ', '.join(self.allowed_mimetypes)
    }

    raise ValidationError(message)

    # Check the file size
    filesize = value.file._size
    if filesize > self.max_size:
    message = self.max_size_message % {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.max_size)
    }

    raise ValidationError(message)

    elif filesize < self.min_size:
    message = self.min_size_message % {
    'size': filesizeformat(filesize),
    'allowed_size': filesizeformat(self.min_size)
    }

    raise ValidationError(message)

    return value