class URLValidator(DjangoURLValidator): """ Set validation regex rules for URLs. """ ul = '\u00a1-\uffff' # unicode letters range (must not be a raw string) # IP patterns ipv4_re = r'(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}' ipv6_re = r'\[[0-9a-f:\.]+\]' # (simple regex, validated later) # Host patterns hostname_re = r'[a-z' + ul + r'0-9](?:[a-z' + ul + r'0-9-]{0,61}[a-z' + ul + r'0-9])?' # Max length for domain name labels is 63 characters per RFC 1034 sec. 3.1 domain_re = r'(?:\.(?!-)[a-z' + ul + r'0-9-]{1,63}(?<!-))*' tld_re = ( r'\.' # dot r'(?!-)' # can't start with a dash r'(?:[a-z' + ul + '-]{2,63}' # domain label r'|xn--[a-z0-9]{1,59})' # or punycode label r'(?<!-)' # can't end with a dash r'\.?' # may have a trailing dot ) host_re = '(' + hostname_re + domain_re + tld_re + '|localhost|testserver)' regex = _lazy_re_compile( r'^(?:[a-z0-9\.\-\+]*)://' # scheme is validated separately r'(?:\S+(?::\S*)?@)?' # user:pass authentication r'(?:' + ipv4_re + '|' + ipv6_re + '|' + host_re + ')' r'(?::\d{2,5})?' # port r'(?:[/?#][^\s]*)?' # resource path r'\Z', re.IGNORECASE) message = _('Enter a valid URL.') schemes = ['http', 'https', 'ftp', 'ftps']
class FQDNValidator: message = _('Enter a valid FQDN.') code = 'invalid' def __init__(self, **kwargs): super().__init__(**kwargs) def __call__(self, value): fqdn = FQDN(value) if not fqdn.is_valid: raise ValidationError(self.message, code=self.code)
class RegexValidator: 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, str): raise TypeError( "If the flags are set, regex must be a regular expression string." ) self.regex = _lazy_re_compile(self.regex, self.flags) def __call__(self, value): """ Validate that the input contains (or does *not* contain, if inverse_match is True) a match for the regular expression. """ regex_matches = self.regex.search(str(value)) invalid_input = regex_matches if self.inverse_match else not regex_matches if invalid_input: 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))
class FQDNField(CharField): default_validators = [FQDNValidator()] description = _("FQDN") def __init__(self, verbose_name=None, name=None, **kwargs): kwargs.setdefault('max_length', 200) super().__init__(verbose_name, name, **kwargs) def deconstruct(self): name, path, args, kwargs = super().deconstruct() if kwargs.get("max_length") == 200: del kwargs['max_length'] return name, path, args, kwargs def formfield(self, **kwargs): # As with CharField, this will cause URL validation to be performed # twice. return super().formfield(**{ 'form_class': forms.URLField, **kwargs, })
class URLValidator(DjangoURLValidator): """ Set validation regex rules for URLs. """ ul = "\u00a1-\uffff" # unicode letters range (must not be a raw string) # IP patterns ipv4_re = ( r"(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}" ) ipv6_re = r"\[[0-9a-f:\.]+\]" # (simple regex, validated later) # Host patterns hostname_re = (r"[a-z" + ul + r"0-9](?:[a-z" + ul + r"0-9-]{0,61}[a-z" + ul + r"0-9])?") # Max length for domain name labels is 63 characters per RFC 1034 sec. 3.1 domain_re = r"(?:\.(?!-)[a-z" + ul + r"0-9-]{1,63}(?<!-))*" tld_re = ( r"\." # dot r"(?!-)" # can't start with a dash r"(?:[a-z" + ul + "-]{2,63}" # domain label r"|xn--[a-z0-9]{1,59})" # or punycode label r"(?<!-)" # can't end with a dash r"\.?" # may have a trailing dot ) host_re = "(" + hostname_re + domain_re + tld_re + "|localhost|testserver)" regex = _lazy_re_compile( r"^(?:[a-z0-9\.\-\+]*)://" # scheme is validated separately r"(?:\S+(?::\S*)?@)?" # user:pass authentication r"(?:" + ipv4_re + "|" + ipv6_re + "|" + host_re + ")" r"(?::\d{2,5})?" # port r"(?:[/?#][^\s]*)?" # resource path r"\Z", re.IGNORECASE, ) message = _("Enter a valid URL.") schemes = ["http", "https", "ftp", "ftps"]
# -*- coding: utf-8 -*- import re from django.core.validators import RegexValidator, _ try: from django.core.validators import _lazy_re_compile code_re = _lazy_re_compile(r'^[A-Z_]+\Z') except ImportError: code_re = re.compile(r'^[A-Z_]+\Z') validate_feature_toggle_code = RegexValidator( code_re, _("Enter a valid 'code' of CAPITAL letters and underscores only."), 'invalid')