Loading django/core/validators.py +14 −2 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ class RegexValidator(object): @deconstructible class URLValidator(RegexValidator): regex = re.compile( r'^(?:http|ftp)s?://' # http:// or https:// 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,}\.?)|' # domain... r'localhost|' # localhost... r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4 Loading @@ -52,14 +52,26 @@ class URLValidator(RegexValidator): r'(?::\d+)?' # optional port r'(?:/?|[/?]\S+)$', re.IGNORECASE) message = _('Enter a valid URL.') schemes = ['http', 'https', 'ftp', 'ftps'] def __init__(self, schemes=None, **kwargs): super(URLValidator, self).__init__(**kwargs) if schemes is not None: self.schemes = schemes def __call__(self, value): value = force_text(value) # Check first if the scheme is valid scheme = value.split('://')[0].lower() if scheme not in self.schemes: raise ValidationError(self.message, code=self.code) # Then check full URL try: super(URLValidator, self).__call__(value) except ValidationError as e: # Trivial case failed. Try for possible IDN domain if value: value = force_text(value) scheme, netloc, path, query, fragment = urlsplit(value) try: netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE Loading docs/ref/validators.txt +16 −2 Original line number Diff line number Diff line Loading @@ -87,10 +87,24 @@ to, or in lieu of custom ``field.clean()`` methods. ``URLValidator`` ---------------- .. class:: URLValidator() .. class:: URLValidator([schemes=None, regex=None, message=None, code=None]) A :class:`RegexValidator` that ensures a value looks like a URL, and raises an error code of ``'invalid'`` if it doesn't. an error code of ``'invalid'`` if it doesn't. In addition to the optional arguments of its parent :class:`RegexValidator` class, ``URLValidator`` accepts an extra optional attribute: .. attribute:: schemes URL/URI scheme list to validate against. If not provided, the default list is ``['http', 'https', 'ftp', 'ftps']``. As a reference, the IANA Web site provides a full list of `valid URI schemes`_. .. _valid URI schemes: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml .. versionchanged:: 1.7 The optional ``schemes`` attribute was added. ``validate_email`` ------------------ Loading docs/releases/1.7.txt +7 −0 Original line number Diff line number Diff line Loading @@ -567,6 +567,13 @@ Tests * :meth:`~django.test.TransactionTestCase.assertNumQueries` now prints out the list of executed queries if the assertion fails. Validators ^^^^^^^^^^ * :class:`~django.core.validators.URLValidator` now accepts an optional ``schemes`` argument which allows customization of the accepted URI schemes (instead of the defaults ``http(s)`` and ``ftp(s)``). Backwards incompatible changes in 1.7 ===================================== Loading tests/validators/tests.py +7 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ from django.test.utils import str_prefix NOW = datetime.now() EXTENDED_SCHEMES = ['http', 'https', 'ftp', 'ftps', 'git', 'file'] TEST_DATA = ( # (validator, value, expected), Loading Loading @@ -141,6 +142,7 @@ TEST_DATA = ( (MinLengthValidator(10), '', ValidationError), (URLValidator(), 'http://www.djangoproject.com/', None), (URLValidator(), 'HTTP://WWW.DJANGOPROJECT.COM/', None), (URLValidator(), 'http://localhost/', None), (URLValidator(), 'http://example.com/', None), (URLValidator(), 'http://www.example.com/', None), Loading @@ -155,6 +157,8 @@ TEST_DATA = ( (URLValidator(), 'https://example.com/', None), (URLValidator(), 'ftp://example.com/', None), (URLValidator(), 'ftps://example.com/', None), (URLValidator(EXTENDED_SCHEMES), 'file://localhost/path', None), (URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None), (URLValidator(), 'foo', ValidationError), (URLValidator(), 'http://', ValidationError), Loading @@ -165,6 +169,9 @@ TEST_DATA = ( (URLValidator(), 'http://-invalid.com', ValidationError), (URLValidator(), 'http://inv-.alid-.com', ValidationError), (URLValidator(), 'http://inv-.-alid.com', ValidationError), (URLValidator(), 'file://localhost/path', ValidationError), (URLValidator(), 'git://example.com/', ValidationError), (URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError), (BaseValidator(True), True, None), (BaseValidator(True), False, ValidationError), Loading Loading
django/core/validators.py +14 −2 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ class RegexValidator(object): @deconstructible class URLValidator(RegexValidator): regex = re.compile( r'^(?:http|ftp)s?://' # http:// or https:// 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,}\.?)|' # domain... r'localhost|' # localhost... r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4 Loading @@ -52,14 +52,26 @@ class URLValidator(RegexValidator): r'(?::\d+)?' # optional port r'(?:/?|[/?]\S+)$', re.IGNORECASE) message = _('Enter a valid URL.') schemes = ['http', 'https', 'ftp', 'ftps'] def __init__(self, schemes=None, **kwargs): super(URLValidator, self).__init__(**kwargs) if schemes is not None: self.schemes = schemes def __call__(self, value): value = force_text(value) # Check first if the scheme is valid scheme = value.split('://')[0].lower() if scheme not in self.schemes: raise ValidationError(self.message, code=self.code) # Then check full URL try: super(URLValidator, self).__call__(value) except ValidationError as e: # Trivial case failed. Try for possible IDN domain if value: value = force_text(value) scheme, netloc, path, query, fragment = urlsplit(value) try: netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE Loading
docs/ref/validators.txt +16 −2 Original line number Diff line number Diff line Loading @@ -87,10 +87,24 @@ to, or in lieu of custom ``field.clean()`` methods. ``URLValidator`` ---------------- .. class:: URLValidator() .. class:: URLValidator([schemes=None, regex=None, message=None, code=None]) A :class:`RegexValidator` that ensures a value looks like a URL, and raises an error code of ``'invalid'`` if it doesn't. an error code of ``'invalid'`` if it doesn't. In addition to the optional arguments of its parent :class:`RegexValidator` class, ``URLValidator`` accepts an extra optional attribute: .. attribute:: schemes URL/URI scheme list to validate against. If not provided, the default list is ``['http', 'https', 'ftp', 'ftps']``. As a reference, the IANA Web site provides a full list of `valid URI schemes`_. .. _valid URI schemes: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml .. versionchanged:: 1.7 The optional ``schemes`` attribute was added. ``validate_email`` ------------------ Loading
docs/releases/1.7.txt +7 −0 Original line number Diff line number Diff line Loading @@ -567,6 +567,13 @@ Tests * :meth:`~django.test.TransactionTestCase.assertNumQueries` now prints out the list of executed queries if the assertion fails. Validators ^^^^^^^^^^ * :class:`~django.core.validators.URLValidator` now accepts an optional ``schemes`` argument which allows customization of the accepted URI schemes (instead of the defaults ``http(s)`` and ``ftp(s)``). Backwards incompatible changes in 1.7 ===================================== Loading
tests/validators/tests.py +7 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ from django.test.utils import str_prefix NOW = datetime.now() EXTENDED_SCHEMES = ['http', 'https', 'ftp', 'ftps', 'git', 'file'] TEST_DATA = ( # (validator, value, expected), Loading Loading @@ -141,6 +142,7 @@ TEST_DATA = ( (MinLengthValidator(10), '', ValidationError), (URLValidator(), 'http://www.djangoproject.com/', None), (URLValidator(), 'HTTP://WWW.DJANGOPROJECT.COM/', None), (URLValidator(), 'http://localhost/', None), (URLValidator(), 'http://example.com/', None), (URLValidator(), 'http://www.example.com/', None), Loading @@ -155,6 +157,8 @@ TEST_DATA = ( (URLValidator(), 'https://example.com/', None), (URLValidator(), 'ftp://example.com/', None), (URLValidator(), 'ftps://example.com/', None), (URLValidator(EXTENDED_SCHEMES), 'file://localhost/path', None), (URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None), (URLValidator(), 'foo', ValidationError), (URLValidator(), 'http://', ValidationError), Loading @@ -165,6 +169,9 @@ TEST_DATA = ( (URLValidator(), 'http://-invalid.com', ValidationError), (URLValidator(), 'http://inv-.alid-.com', ValidationError), (URLValidator(), 'http://inv-.-alid.com', ValidationError), (URLValidator(), 'file://localhost/path', ValidationError), (URLValidator(), 'git://example.com/', ValidationError), (URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError), (BaseValidator(True), True, None), (BaseValidator(True), False, ValidationError), Loading