diff --git a/django/contrib/auth/tests/forms.py b/django/contrib/auth/tests/forms.py index 7b12491683..2c8f6e4faf 100644 --- a/django/contrib/auth/tests/forms.py +++ b/django/contrib/auth/tests/forms.py @@ -7,7 +7,7 @@ from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm, ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget) from django.contrib.auth.tests.utils import skipIfCustomUser from django.core import mail -from django.forms.fields import Field, EmailField, CharField +from django.forms.fields import Field, CharField from django.test import TestCase from django.test.utils import override_settings from django.utils.encoding import force_text @@ -322,8 +322,7 @@ class PasswordResetFormTest(TestCase): data = {'email': 'not valid'} form = PasswordResetForm(data) self.assertFalse(form.is_valid()) - self.assertEqual(form['email'].errors, - [force_text(EmailField.default_error_messages['invalid'])]) + self.assertEqual(form['email'].errors, [_('Enter a valid email address.')]) def test_nonexistant_email(self): # Test nonexistant email address. This should not fail because it would diff --git a/django/core/validators.py b/django/core/validators.py index 3067b551da..d0b713be32 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -80,7 +80,7 @@ def validate_integer(value): class EmailValidator(object): - message = _('Enter a valid e-mail address.') + message = _('Enter a valid email address.') code = 'invalid' user_regex = re.compile( r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" # dot-atom diff --git a/django/forms/fields.py b/django/forms/fields.py index 4a07dc3542..11b7f44029 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -49,9 +49,10 @@ class Field(object): widget = TextInput # Default widget to use when rendering this type of Field. hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". default_validators = [] # Default set of validators + # Add an 'invalid' entry to default_error_message if you want a specific + # field error message not raised by the field validators. default_error_messages = { 'required': _('This field is required.'), - 'invalid': _('Enter a valid value.'), } empty_values = list(validators.EMPTY_VALUES) @@ -225,8 +226,6 @@ class CharField(Field): class IntegerField(Field): default_error_messages = { 'invalid': _('Enter a whole number.'), - 'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'), - 'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'), } def __init__(self, max_value=None, min_value=None, *args, **kwargs): @@ -504,9 +503,6 @@ class RegexField(CharField): class EmailField(CharField): widget = EmailInput - default_error_messages = { - 'invalid': _('Enter a valid email address.'), - } default_validators = [validators.validate_email] def clean(self, value): @@ -1082,9 +1078,6 @@ class SplitDateTimeField(MultiValueField): class IPAddressField(CharField): - default_error_messages = { - 'invalid': _('Enter a valid IPv4 address.'), - } default_validators = [validators.validate_ipv4_address] def to_python(self, value): @@ -1094,13 +1087,9 @@ class IPAddressField(CharField): class GenericIPAddressField(CharField): - default_error_messages = {} - def __init__(self, protocol='both', unpack_ipv4=False, *args, **kwargs): self.unpack_ipv4 = unpack_ipv4 - self.default_validators, invalid_error_message = \ - validators.ip_address_validators(protocol, unpack_ipv4) - self.default_error_messages['invalid'] = invalid_error_message + self.default_validators = validators.ip_address_validators(protocol, unpack_ipv4)[0] super(GenericIPAddressField, self).__init__(*args, **kwargs) def to_python(self, value): @@ -1108,14 +1097,9 @@ class GenericIPAddressField(CharField): return '' value = value.strip() if value and ':' in value: - return clean_ipv6_address(value, - self.unpack_ipv4, self.error_messages['invalid']) + return clean_ipv6_address(value, self.unpack_ipv4) return value class SlugField(CharField): - default_error_messages = { - 'invalid': _("Enter a valid 'slug' consisting of letters, numbers," - " underscores or hyphens."), - } default_validators = [validators.validate_slug] diff --git a/django/utils/ipv6.py b/django/utils/ipv6.py index 7624bb9c76..8881574eaa 100644 --- a/django/utils/ipv6.py +++ b/django/utils/ipv6.py @@ -5,7 +5,7 @@ from django.core.exceptions import ValidationError from django.utils.six.moves import xrange def clean_ipv6_address(ip_str, unpack_ipv4=False, - error_message="This is not a valid IPv6 address"): + error_message="This is not a valid IPv6 address."): """ Cleans a IPv6 address string. diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt index e89bce748f..978c985b55 100644 --- a/docs/ref/forms/validation.txt +++ b/docs/ref/forms/validation.txt @@ -181,24 +181,20 @@ the field's ``validators`` argument, or defined on the Field class itself with the ``default_validators`` attribute. Simple validators can be used to validate values inside the field, let's have -a look at Django's ``EmailField``:: +a look at Django's ``SlugField``:: - class EmailField(CharField): - default_error_messages = { - 'invalid': _('Enter a valid email address.'), - } - default_validators = [validators.validate_email] + class SlugField(CharField): + default_validators = [validators.validate_slug] -As you can see, ``EmailField`` is just a ``CharField`` with customized error -message and a validator that validates email addresses. This can also be done -on field definition so:: +As you can see, ``SlugField`` is just a ``CharField`` with a customized +validator that validates that submitted text obeys to some character rules. +This can also be done on field definition so:: - email = forms.EmailField() + slug = forms.SlugField() is equivalent to:: - email = forms.CharField(validators=[validators.validate_email], - error_messages={'invalid': _('Enter a valid email address.')}) + slug = forms.CharField(validators=[validators.validate_slug]) Form field default cleaning diff --git a/tests/forms_tests/tests/extra.py b/tests/forms_tests/tests/extra.py index 359ad442bc..427d099bb2 100644 --- a/tests/forms_tests/tests/extra.py +++ b/tests/forms_tests/tests/extra.py @@ -506,11 +506,11 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '256.125.1.5') self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a') self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '12345:2:3:4') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1::2:3::4') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1::2:3:4:5:6:7:8') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1:2') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '12345:2:3:4') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1::2:3::4') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1::2:3:4:5:6:7:8') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1:2') def test_generic_ipaddress_as_ipv4_only(self): f = GenericIPAddressField(protocol="IPv4") @@ -535,11 +535,11 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '256.125.1.5') self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a') self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') - self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '12345:2:3:4') - self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '1::2:3::4') - self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a') - self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '1::2:3:4:5:6:7:8') - self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '1:2') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '12345:2:3:4') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1::2:3::4') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1::2:3:4:5:6:7:8') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1:2') def test_generic_ipaddress_as_generic_not_required(self): f = GenericIPAddressField(required=False) @@ -552,11 +552,11 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '256.125.1.5') self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a') self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '12345:2:3:4') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1::2:3::4') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1::2:3:4:5:6:7:8') - self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1:2') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '12345:2:3:4') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1::2:3::4') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1::2:3:4:5:6:7:8') + self.assertFormErrors(['This is not a valid IPv6 address.'], f.clean, '1:2') def test_generic_ipaddress_normalization(self): # Test the normalising code diff --git a/tests/forms_tests/tests/validators.py b/tests/forms_tests/tests/validators.py index a4cb324815..0598835cff 100644 --- a/tests/forms_tests/tests/validators.py +++ b/tests/forms_tests/tests/validators.py @@ -1,16 +1,39 @@ +from __future__ import unicode_literals + from django import forms from django.core import validators from django.core.exceptions import ValidationError from django.utils.unittest import TestCase +class UserForm(forms.Form): + full_name = forms.CharField( + max_length = 50, + validators = [ + validators.validate_integer, + validators.validate_email, + ] + ) + string = forms.CharField( + max_length = 50, + validators = [ + validators.RegexValidator( + regex='^[a-zA-Z]*$', + message="Letters only.", + ) + ] + ) + + class TestFieldWithValidators(TestCase): def test_all_errors_get_reported(self): - field = forms.CharField( - validators=[validators.validate_integer, validators.validate_email] - ) - self.assertRaises(ValidationError, field.clean, 'not int nor mail') + form = UserForm({'full_name': 'not int nor mail', 'string': '2 is not correct'}) + self.assertRaises(ValidationError, form.fields['full_name'].clean, 'not int nor mail') + try: - field.clean('not int nor mail') + form.fields['full_name'].clean('not int nor mail') except ValidationError as e: self.assertEqual(2, len(e.messages)) + + self.assertFalse(form.is_valid()) + self.assertEqual(form.errors['string'], ["Letters only."])