from __future__ import unicode_literals import re from django.core.exceptions import ValidationError from django.utils.deconstruct import deconstructible from django.utils.translation import ugettext_lazy as _, ungettext_lazy from django.utils.encoding import force_text from django.utils.ipv6 import is_valid_ipv6_address from django.utils import six from django.utils.six.moves.urllib.parse import urlsplit, urlunsplit # These values, if given to validate(), will trigger the self.required check. EMPTY_VALUES = (None, '', [], (), {}) @deconstructible class RegexValidator(object): regex = '' message = _('Enter a valid value.') code = 'invalid' inverse_match = False flags = 0 def __init__(self, regex=None, message=None, code=None, inverse_match=None, flags=None): if regex is not None: self.regex = regex if message is not None: self.message = message if code is not None: self.code = code if inverse_match is not None: self.inverse_match = inverse_match if flags is not None: self.flags = flags if self.flags and not isinstance(self.regex, six.string_types): raise TypeError("If the flags are set, regex must be a regular expression string.") # Compile the regex if it was not passed pre-compiled. if isinstance(self.regex, six.string_types): self.regex = re.compile(self.regex, self.flags) def __call__(self, value): """ Validates that the input matches the regular expression if inverse_match is False, otherwise raises ValidationError. """ if not (self.inverse_match is not bool(self.regex.search( force_text(value)))): raise ValidationError(self.message, code=self.code) def __eq__(self, other): return ( isinstance(other, RegexValidator) and self.regex.pattern == other.regex.pattern and self.regex.flags == other.regex.flags and (self.message == other.message) and (self.code == other.code) and (self.inverse_match == other.inverse_match) ) def __ne__(self, other): return not (self == other) @deconstructible class URLValidator(RegexValidator): regex = re.compile( r'^(?:[a-z0-9\.\-]*)://' # scheme is validated separately r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(? ACE except UnicodeError: # invalid domain part raise e url = urlunsplit((scheme, netloc, path, query, fragment)) super(URLValidator, self).__call__(url) else: raise else: url = value def validate_integer(value): try: int(value) except (ValueError, TypeError): raise ValidationError(_('Enter a valid integer.'), code='invalid') @deconstructible class EmailValidator(object): message = _('Enter a valid email address.') code = 'invalid' user_regex = re.compile( r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" # dot-atom r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', # quoted-string re.IGNORECASE) domain_regex = re.compile( # max length of the domain is 249: 254 (max email length) minus one # period, two characters for the TLD, @ sign, & one character before @. r'(?:[A-Z0-9](?:[A-Z0-9-]{0,247}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(? b message = _('Ensure this value is less than or equal to %(limit_value)s.') code = 'max_value' @deconstructible class MinValueValidator(BaseValidator): compare = lambda self, a, b: a < b message = _('Ensure this value is greater than or equal to %(limit_value)s.') code = 'min_value' @deconstructible class MinLengthValidator(BaseValidator): compare = lambda self, a, b: a < b clean = lambda self, x: len(x) message = ungettext_lazy( 'Ensure this value has at least %(limit_value)d character (it has %(show_value)d).', 'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).', 'limit_value') code = 'min_length' @deconstructible class MaxLengthValidator(BaseValidator): compare = lambda self, a, b: a > b clean = lambda self, x: len(x) message = ungettext_lazy( 'Ensure this value has at most %(limit_value)d character (it has %(show_value)d).', 'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).', 'limit_value') code = 'max_length'