Loading django/core/validators.py +7 −2 Original line number Diff line number Diff line Loading @@ -21,8 +21,9 @@ class RegexValidator(object): message = _('Enter a valid value.') code = 'invalid' inverse_match = False flags = 0 def __init__(self, regex=None, message=None, code=None, inverse_match=None): 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: Loading @@ -31,10 +32,14 @@ class RegexValidator(object): 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.regex = re.compile(self.regex, self.flags) def __call__(self, value): """ Loading docs/ref/validators.txt +13 −1 Original line number Diff line number Diff line Loading @@ -59,13 +59,16 @@ to, or in lieu of custom ``field.clean()`` methods. ``RegexValidator`` ------------------ .. class:: RegexValidator([regex=None, message=None, code=None, inverse_match=None]) .. class:: RegexValidator([regex=None, message=None, code=None, inverse_match=None, flags=0]) :param regex: If not ``None``, overrides :attr:`regex`. Can be a regular expression string or a pre-compiled regular expression. :param message: If not ``None``, overrides :attr:`.message`. :param code: If not ``None``, overrides :attr:`code`. :param inverse_match: If not ``None``, overrides :attr:`inverse_match`. :param flags: If not ``None``, overrides :attr:`flags`. In that case, :attr:`regex` must be a regular expression string, or :exc:`~exceptions.TypeError` is raised. .. attribute:: regex Loading Loading @@ -93,6 +96,15 @@ to, or in lieu of custom ``field.clean()`` methods. The match mode for :attr:`regex`. Defaults to ``False``. .. attribute:: flags .. versionadded:: 1.7 The flags used when compiling the regular expression string :attr:`regex`. If :attr:`regex` is a pre-compiled regular expression, and :attr:`flags` is overridden, :exc:`~exceptions.TypeError` is raised. Defaults to `0`. ``URLValidator`` ---------------- .. class:: URLValidator([schemes=None, regex=None, message=None, code=None]) Loading docs/releases/1.7.txt +15 −4 Original line number Diff line number Diff line Loading @@ -795,11 +795,15 @@ Tests Validators ^^^^^^^^^^ * :class:`~django.core.validators.RegexValidator` now accepts an optional Boolean :attr:`~django.core.validators.RegexValidator.inverse_match` argument which determines if the :exc:`~django.core.exceptions.ValidationError` should * :class:`~django.core.validators.RegexValidator` now accepts the optional :attr:`~django.core.validators.RegexValidator.flags` and Boolean :attr:`~django.core.validators.RegexValidator.inverse_match` arguments. The :attr:`~django.core.validators.RegexValidator.inverse_match` attribute determines if the :exc:`~django.core.exceptions.ValidationError` should be raised when the regular expression pattern matches (``True``) or does not match (``False``, by default) the provided ``value``. match (``False``, by default) the provided ``value``. The :attr:`~django.core.validators.RegexValidator.flags` attribute sets the flags used when compiling a regular expression string. * :class:`~django.core.validators.URLValidator` now accepts an optional ``schemes`` argument which allows customization of the accepted URI schemes Loading Loading @@ -1191,6 +1195,13 @@ Miscellaneous a relation from the related object back to the content type for filtering, ordering and other query operations. * When a model field's :attr:`~django.db.models.Field.validators` contains a :class:`~django.core.validators.RegexValidator`, the regular expression must now be passed as a regular expression string. You can no longer use a pre-compiled regular expression in this case, as it is not serializable. The :attr:`~django.core.validators.RegexValidator.flags` attribute was added to :class:`~django.core.validators.RegexValidator` to simplify this change. .. _deprecated-features-1.7: Features deprecated in 1.7 Loading tests/forms_tests/tests/test_validators.py +14 −1 Original line number Diff line number Diff line from __future__ import unicode_literals import re from unittest import TestCase from django import forms Loading @@ -24,11 +25,22 @@ class UserForm(forms.Form): ) ] ) ignore_case_string = forms.CharField( max_length=50, validators=[ validators.RegexValidator( regex='^[a-z]*$', message="Letters only.", flags=re.IGNORECASE, ) ] ) class TestFieldWithValidators(TestCase): def test_all_errors_get_reported(self): form = UserForm({'full_name': 'not int nor mail', 'string': '2 is not correct'}) form = UserForm({'full_name': 'not int nor mail', 'string': '2 is not correct', 'ignore_case_string': "IgnORE Case strIng"}) self.assertRaises(ValidationError, form.fields['full_name'].clean, 'not int nor mail') try: Loading @@ -38,3 +50,4 @@ class TestFieldWithValidators(TestCase): self.assertFalse(form.is_valid()) self.assertEqual(form.errors['string'], ["Letters only."]) self.assertEqual(form.errors['string'], ["Letters only."]) tests/validators/tests.py +12 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,10 @@ TEST_DATA = ( (RegexValidator(re.compile('x'), inverse_match=True), 'y', None), (RegexValidator('x', inverse_match=True), 'x', ValidationError), (RegexValidator(re.compile('x'), inverse_match=True), 'x', ValidationError), (RegexValidator('x', flags=re.IGNORECASE), 'y', ValidationError), (RegexValidator('a'), 'A', ValidationError), (RegexValidator('a', flags=re.IGNORECASE), 'A', None), ) Loading Loading @@ -250,6 +254,14 @@ class TestSimpleValidators(TestCase): self.assertEqual(str(v), str_prefix("{%(_)s'first': [%(_)s'First Problem']}")) self.assertEqual(repr(v), str_prefix("ValidationError({%(_)s'first': [%(_)s'First Problem']})")) def test_regex_validator_flags(self): try: RegexValidator(re.compile('a'), flags=re.IGNORECASE) except TypeError: pass else: self.fail("TypeError not raised when flags and pre-compiled regex in RegexValidator") test_counter = 0 for validator, value, expected in TEST_DATA: name, method = create_simple_test_method(validator, expected, value, test_counter) Loading Loading
django/core/validators.py +7 −2 Original line number Diff line number Diff line Loading @@ -21,8 +21,9 @@ class RegexValidator(object): message = _('Enter a valid value.') code = 'invalid' inverse_match = False flags = 0 def __init__(self, regex=None, message=None, code=None, inverse_match=None): 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: Loading @@ -31,10 +32,14 @@ class RegexValidator(object): 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.regex = re.compile(self.regex, self.flags) def __call__(self, value): """ Loading
docs/ref/validators.txt +13 −1 Original line number Diff line number Diff line Loading @@ -59,13 +59,16 @@ to, or in lieu of custom ``field.clean()`` methods. ``RegexValidator`` ------------------ .. class:: RegexValidator([regex=None, message=None, code=None, inverse_match=None]) .. class:: RegexValidator([regex=None, message=None, code=None, inverse_match=None, flags=0]) :param regex: If not ``None``, overrides :attr:`regex`. Can be a regular expression string or a pre-compiled regular expression. :param message: If not ``None``, overrides :attr:`.message`. :param code: If not ``None``, overrides :attr:`code`. :param inverse_match: If not ``None``, overrides :attr:`inverse_match`. :param flags: If not ``None``, overrides :attr:`flags`. In that case, :attr:`regex` must be a regular expression string, or :exc:`~exceptions.TypeError` is raised. .. attribute:: regex Loading Loading @@ -93,6 +96,15 @@ to, or in lieu of custom ``field.clean()`` methods. The match mode for :attr:`regex`. Defaults to ``False``. .. attribute:: flags .. versionadded:: 1.7 The flags used when compiling the regular expression string :attr:`regex`. If :attr:`regex` is a pre-compiled regular expression, and :attr:`flags` is overridden, :exc:`~exceptions.TypeError` is raised. Defaults to `0`. ``URLValidator`` ---------------- .. class:: URLValidator([schemes=None, regex=None, message=None, code=None]) Loading
docs/releases/1.7.txt +15 −4 Original line number Diff line number Diff line Loading @@ -795,11 +795,15 @@ Tests Validators ^^^^^^^^^^ * :class:`~django.core.validators.RegexValidator` now accepts an optional Boolean :attr:`~django.core.validators.RegexValidator.inverse_match` argument which determines if the :exc:`~django.core.exceptions.ValidationError` should * :class:`~django.core.validators.RegexValidator` now accepts the optional :attr:`~django.core.validators.RegexValidator.flags` and Boolean :attr:`~django.core.validators.RegexValidator.inverse_match` arguments. The :attr:`~django.core.validators.RegexValidator.inverse_match` attribute determines if the :exc:`~django.core.exceptions.ValidationError` should be raised when the regular expression pattern matches (``True``) or does not match (``False``, by default) the provided ``value``. match (``False``, by default) the provided ``value``. The :attr:`~django.core.validators.RegexValidator.flags` attribute sets the flags used when compiling a regular expression string. * :class:`~django.core.validators.URLValidator` now accepts an optional ``schemes`` argument which allows customization of the accepted URI schemes Loading Loading @@ -1191,6 +1195,13 @@ Miscellaneous a relation from the related object back to the content type for filtering, ordering and other query operations. * When a model field's :attr:`~django.db.models.Field.validators` contains a :class:`~django.core.validators.RegexValidator`, the regular expression must now be passed as a regular expression string. You can no longer use a pre-compiled regular expression in this case, as it is not serializable. The :attr:`~django.core.validators.RegexValidator.flags` attribute was added to :class:`~django.core.validators.RegexValidator` to simplify this change. .. _deprecated-features-1.7: Features deprecated in 1.7 Loading
tests/forms_tests/tests/test_validators.py +14 −1 Original line number Diff line number Diff line from __future__ import unicode_literals import re from unittest import TestCase from django import forms Loading @@ -24,11 +25,22 @@ class UserForm(forms.Form): ) ] ) ignore_case_string = forms.CharField( max_length=50, validators=[ validators.RegexValidator( regex='^[a-z]*$', message="Letters only.", flags=re.IGNORECASE, ) ] ) class TestFieldWithValidators(TestCase): def test_all_errors_get_reported(self): form = UserForm({'full_name': 'not int nor mail', 'string': '2 is not correct'}) form = UserForm({'full_name': 'not int nor mail', 'string': '2 is not correct', 'ignore_case_string': "IgnORE Case strIng"}) self.assertRaises(ValidationError, form.fields['full_name'].clean, 'not int nor mail') try: Loading @@ -38,3 +50,4 @@ class TestFieldWithValidators(TestCase): self.assertFalse(form.is_valid()) self.assertEqual(form.errors['string'], ["Letters only."]) self.assertEqual(form.errors['string'], ["Letters only."])
tests/validators/tests.py +12 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,10 @@ TEST_DATA = ( (RegexValidator(re.compile('x'), inverse_match=True), 'y', None), (RegexValidator('x', inverse_match=True), 'x', ValidationError), (RegexValidator(re.compile('x'), inverse_match=True), 'x', ValidationError), (RegexValidator('x', flags=re.IGNORECASE), 'y', ValidationError), (RegexValidator('a'), 'A', ValidationError), (RegexValidator('a', flags=re.IGNORECASE), 'A', None), ) Loading Loading @@ -250,6 +254,14 @@ class TestSimpleValidators(TestCase): self.assertEqual(str(v), str_prefix("{%(_)s'first': [%(_)s'First Problem']}")) self.assertEqual(repr(v), str_prefix("ValidationError({%(_)s'first': [%(_)s'First Problem']})")) def test_regex_validator_flags(self): try: RegexValidator(re.compile('a'), flags=re.IGNORECASE) except TypeError: pass else: self.fail("TypeError not raised when flags and pre-compiled regex in RegexValidator") test_counter = 0 for validator, value, expected in TEST_DATA: name, method = create_simple_test_method(validator, expected, value, test_counter) Loading