Loading django/core/validators.py +44 −21 Original line number Diff line number Diff line Loading @@ -78,30 +78,53 @@ def validate_integer(value): raise ValidationError('') class EmailValidator(RegexValidator): class EmailValidator(object): message = _('Enter a valid e-mail 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( r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' # domain # literal form, ipv4 address (SMTP 4.1.3) r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) domain_whitelist = ['localhost'] def __init__(self, message=None, code=None, whitelist=None): if message is not None: self.message = message if code is not None: self.code = code if whitelist is not None: self.domain_whitelist = whitelist def __call__(self, value): value = force_text(value) if not value or '@' not in value: raise ValidationError(self.message, code=self.code) user_part, domain_part = value.split('@', 1) if not self.user_regex.match(user_part): raise ValidationError(self.message, code=self.code) if (not domain_part in self.domain_whitelist and not self.domain_regex.match(domain_part)): # Try for possible IDN domain-part try: super(EmailValidator, self).__call__(value) except ValidationError as e: # Trivial case failed. Try for possible IDN domain-part if value and '@' in value: parts = value.split('@') try: parts[-1] = parts[-1].encode('idna').decode('ascii') except UnicodeError: raise e super(EmailValidator, self).__call__('@'.join(parts)) domain_part = domain_part.encode('idna').decode('ascii') if not self.domain_regex.match(domain_part): raise ValidationError(self.message, code=self.code) else: raise return except UnicodeError: pass raise ValidationError(self.message, code=self.code) email_re = re.compile( r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)$)' # domain r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3) validate_email = EmailValidator(email_re, _('Enter a valid email address.'), 'invalid') validate_email = EmailValidator() slug_re = re.compile(r'^[-a-zA-Z0-9_]+$') validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid') Loading docs/ref/validators.txt +1 −1 Original line number Diff line number Diff line Loading @@ -96,7 +96,7 @@ to, or in lieu of custom ``field.clean()`` methods. ------------------ .. data:: validate_email A :class:`RegexValidator` instance that ensures a value looks like an An ``EmailValidator`` instance that ensures a value looks like an email address. ``validate_slug`` Loading tests/modeltests/validators/tests.py +2 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ TEST_DATA = ( (validate_email, 'example@valid-----hyphens.com', None), (validate_email, 'example@valid-with-hyphens.com', None), (validate_email, 'test@domain.with.idn.tld.उदाहरण.परीक्षा', None), (validate_email, 'email@localhost', None), (EmailValidator(whitelist=['localdomain']), 'email@localdomain', None), (validate_email, None, ValidationError), (validate_email, '', ValidationError), Loading Loading
django/core/validators.py +44 −21 Original line number Diff line number Diff line Loading @@ -78,30 +78,53 @@ def validate_integer(value): raise ValidationError('') class EmailValidator(RegexValidator): class EmailValidator(object): message = _('Enter a valid e-mail 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( r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' # domain # literal form, ipv4 address (SMTP 4.1.3) r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) domain_whitelist = ['localhost'] def __init__(self, message=None, code=None, whitelist=None): if message is not None: self.message = message if code is not None: self.code = code if whitelist is not None: self.domain_whitelist = whitelist def __call__(self, value): value = force_text(value) if not value or '@' not in value: raise ValidationError(self.message, code=self.code) user_part, domain_part = value.split('@', 1) if not self.user_regex.match(user_part): raise ValidationError(self.message, code=self.code) if (not domain_part in self.domain_whitelist and not self.domain_regex.match(domain_part)): # Try for possible IDN domain-part try: super(EmailValidator, self).__call__(value) except ValidationError as e: # Trivial case failed. Try for possible IDN domain-part if value and '@' in value: parts = value.split('@') try: parts[-1] = parts[-1].encode('idna').decode('ascii') except UnicodeError: raise e super(EmailValidator, self).__call__('@'.join(parts)) domain_part = domain_part.encode('idna').decode('ascii') if not self.domain_regex.match(domain_part): raise ValidationError(self.message, code=self.code) else: raise return except UnicodeError: pass raise ValidationError(self.message, code=self.code) email_re = re.compile( r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)$)' # domain r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3) validate_email = EmailValidator(email_re, _('Enter a valid email address.'), 'invalid') validate_email = EmailValidator() slug_re = re.compile(r'^[-a-zA-Z0-9_]+$') validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid') Loading
docs/ref/validators.txt +1 −1 Original line number Diff line number Diff line Loading @@ -96,7 +96,7 @@ to, or in lieu of custom ``field.clean()`` methods. ------------------ .. data:: validate_email A :class:`RegexValidator` instance that ensures a value looks like an An ``EmailValidator`` instance that ensures a value looks like an email address. ``validate_slug`` Loading
tests/modeltests/validators/tests.py +2 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ TEST_DATA = ( (validate_email, 'example@valid-----hyphens.com', None), (validate_email, 'example@valid-with-hyphens.com', None), (validate_email, 'test@domain.with.idn.tld.उदाहरण.परीक्षा', None), (validate_email, 'email@localhost', None), (EmailValidator(whitelist=['localdomain']), 'email@localdomain', None), (validate_email, None, ValidationError), (validate_email, '', ValidationError), Loading