diff --git a/django/forms/fields.py b/django/forms/fields.py
index 113a5aa..4093d15 100644
a
|
b
|
class Field(object):
|
54 | 54 | |
55 | 55 | def __init__(self, required=True, widget=None, label=None, initial=None, |
56 | 56 | help_text=None, error_messages=None, show_hidden_initial=False, |
57 | | validators=[], localize=False): |
| 57 | validators=[], localize=False, normalize=None): |
58 | 58 | # required -- Boolean that specifies whether the field is required. |
59 | 59 | # True by default. |
60 | 60 | # widget -- A Widget class, or instance of a Widget class, that should |
… |
… |
class Field(object):
|
82 | 82 | self.help_text = u'' |
83 | 83 | else: |
84 | 84 | self.help_text = smart_unicode(help_text) |
| 85 | self.normalize = normalize |
85 | 86 | widget = widget or self.widget |
86 | 87 | if isinstance(widget, type): |
87 | 88 | widget = widget() |
… |
… |
class Field(object):
|
149 | 150 | Raises ValidationError for any errors. |
150 | 151 | """ |
151 | 152 | value = self.to_python(value) |
| 153 | if self.normalize: |
| 154 | value = self.normalize(value) |
152 | 155 | self.validate(value) |
153 | 156 | self.run_validators(value) |
154 | 157 | return value |
… |
… |
class EmailField(CharField):
|
450 | 453 | } |
451 | 454 | default_validators = [validators.validate_email] |
452 | 455 | |
453 | | def clean(self, value): |
454 | | value = self.to_python(value).strip() |
455 | | return super(EmailField, self).clean(value) |
| 456 | def __init__(self, *args, **kwargs): |
| 457 | super(EmailField, self).__init__(*args, **kwargs) |
| 458 | if self.normalize is None: |
| 459 | self.normalize = lambda value: value.strip() |
456 | 460 | |
457 | 461 | class FileField(Field): |
458 | 462 | widget = ClearableFileInput |
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index 66c05e5..e1333c3 100644
a
|
b
|
as the rendered output.
|
278 | 278 | See the :ref:`format localization <format-localization>` documentation for |
279 | 279 | more information. |
280 | 280 | |
| 281 | ``normalize`` |
| 282 | ~~~~~~~~~~~~ |
| 283 | |
| 284 | .. versionadded:: New in Django development version |
| 285 | |
| 286 | .. attribute:: Field.normalize |
| 287 | |
| 288 | The ``normalize`` argument lets you normalize the input data before it is validated. |
| 289 | A common use-case is stripping leading and trailinig whitespace from CharFields:: |
| 290 | |
| 291 | >>> foo = forms.CharField(normalize=lambda x: x.strip()) |
| 292 | >>> foo.clean(' ') |
| 293 | Traceback (most recent call last): |
| 294 | ... |
| 295 | ValidationError: [u'This field is required.'] |
| 296 | |
| 297 | |
281 | 298 | .. _built-in fields: |
282 | 299 | |
283 | 300 | Built-in ``Field`` classes |
diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py
index 6780413..37f18ce 100644
a
|
b
|
class FieldsTests(TestCase):
|
131 | 131 | self.assertEqual(f.max_length, None) |
132 | 132 | self.assertEqual(f.min_length, 10) |
133 | 133 | |
| 134 | def test_charfield_normalize(self): |
| 135 | f = CharField(normalize=lambda x: x.strip()) |
| 136 | self.assertRaisesErrorWithMessage(ValidationError, "[u'This field is required.']", f.clean, " \t") |
| 137 | |
134 | 138 | # IntegerField ################################################################ |
135 | 139 | |
136 | 140 | def test_integerfield_1(self): |