Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[1.7.x] Fixed #22255 -- Added support for specifying re flags in Rege…

…xValidator

Backport of 4d0c5f6 from master.
  • Loading branch information...
commit b74ec85c1d4285aa6b3e220c6b55596dd6bdafad 1 parent cc8a800
@dekomote dekomote authored erikr committed
View
9 django/core/validators.py
@@ -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:
@@ -31,10 +32,14 @@ def __init__(self, regex=None, message=None, code=None, inverse_match=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.regex = re.compile(self.regex, self.flags)
def __call__(self, value):
"""
View
14 docs/ref/validators.txt
@@ -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
@@ -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])
View
19 docs/releases/1.7.txt
@@ -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
@@ -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
View
15 tests/forms_tests/tests/test_validators.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+import re
from unittest import TestCase
from django import forms
@@ -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:
@@ -38,3 +50,4 @@ def test_all_errors_get_reported(self):
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['string'], ["Letters only."])
+ self.assertEqual(form.errors['string'], ["Letters only."])
View
12 tests/validators/tests.py
@@ -198,6 +198,10 @@
(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),
)
@@ -250,6 +254,14 @@ def test_message_dict(self):
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)
Please sign in to comment.
Something went wrong with that request. Please try again.