Fixed #4960 -- Added "strip" option to CharField

This commit is contained in:
Curtis 2015-02-05 23:26:15 +11:00 committed by Tim Graham
parent b535eb3fcb
commit 11cac1bd8e
4 changed files with 48 additions and 11 deletions

View File

@ -210,8 +210,10 @@ class Field(six.with_metaclass(RenameFieldMethods, object)):
class CharField(Field): class CharField(Field):
def __init__(self, max_length=None, min_length=None, *args, **kwargs): def __init__(self, max_length=None, min_length=None, strip=True, *args, **kwargs):
self.max_length, self.min_length = max_length, min_length self.max_length = max_length
self.min_length = min_length
self.strip = strip
super(CharField, self).__init__(*args, **kwargs) super(CharField, self).__init__(*args, **kwargs)
if min_length is not None: if min_length is not None:
self.validators.append(validators.MinLengthValidator(int(min_length))) self.validators.append(validators.MinLengthValidator(int(min_length)))
@ -222,7 +224,10 @@ class CharField(Field):
"Returns a Unicode object." "Returns a Unicode object."
if value in self.empty_values: if value in self.empty_values:
return '' return ''
return smart_text(value) value = force_text(value)
if self.strip:
value = value.strip()
return value
def widget_attrs(self, widget): def widget_attrs(self, widget):
attrs = super(CharField, self).widget_attrs(widget) attrs = super(CharField, self).widget_attrs(widget)
@ -539,6 +544,7 @@ class RegexField(CharField):
error_message is an optional error message to use, if error_message is an optional error message to use, if
'Enter a valid value' is too generic for you. 'Enter a valid value' is too generic for you.
""" """
kwargs.setdefault('strip', False)
# error_message is just kept for backwards compatibility: # error_message is just kept for backwards compatibility:
if error_message is not None: if error_message is not None:
warnings.warn( warnings.warn(
@ -1231,10 +1237,6 @@ class GenericIPAddressField(CharField):
class SlugField(CharField): class SlugField(CharField):
default_validators = [validators.validate_slug] default_validators = [validators.validate_slug]
def clean(self, value):
value = self.to_python(value).strip()
return super(SlugField, self).clean(value)
class UUIDField(CharField): class UUIDField(CharField):
default_error_messages = { default_error_messages = {

View File

@ -361,7 +361,7 @@ For each field, we describe the default widget used if you don't specify
Otherwise, all inputs are valid. Otherwise, all inputs are valid.
* Error message keys: ``required``, ``max_length``, ``min_length`` * Error message keys: ``required``, ``max_length``, ``min_length``
Has two optional arguments for validation: Has three optional arguments for validation:
.. attribute:: max_length .. attribute:: max_length
.. attribute:: min_length .. attribute:: min_length
@ -369,6 +369,13 @@ For each field, we describe the default widget used if you don't specify
If provided, these arguments ensure that the string is at most or at least If provided, these arguments ensure that the string is at most or at least
the given length. the given length.
.. attribute:: strip
.. versionadded:: 1.9
If ``True`` (default), the value will be stripped of leading and
trailing whitespace.
``ChoiceField`` ``ChoiceField``
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
@ -824,8 +831,15 @@ For each field, we describe the default widget used if you don't specify
A regular expression specified either as a string or a compiled regular A regular expression specified either as a string or a compiled regular
expression object. expression object.
Also takes ``max_length`` and ``min_length``, which work just as they do for Also takes ``max_length``, ``min_length``, and ``strip``, which work just
``CharField``. as they do for ``CharField``.
.. attribute:: strip
.. versionadded:: 1.9
Defaults to ``False``. If enabled, stripping will be applied before the
regex validation.
.. deprecated:: 1.8 .. deprecated:: 1.8

View File

@ -302,6 +302,11 @@ Forms
* You can now :ref:`specify keyword arguments <custom-formset-form-kwargs>` * You can now :ref:`specify keyword arguments <custom-formset-form-kwargs>`
that you want to pass to the constructor of forms in a formset. that you want to pass to the constructor of forms in a formset.
* :class:`~django.forms.CharField` now accepts a
:attr:`~django.forms.CharField.strip` argument to strip input data of leading
and trailing whitespace. As this defaults to ``True`` this is different
behavior from previous releases.
Generic Views Generic Views
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
@ -552,7 +557,7 @@ Database backend API
SQLite backend to add time lookups (hour, minute, second) to SQLite backend to add time lookups (hour, minute, second) to
:class:`~django.db.models.TimeField`, and may be needed by third-party :class:`~django.db.models.TimeField`, and may be needed by third-party
database backends. database backends.
* The ``DatabaseOperations.datetime_cast_sql()`` method (not to be confused * The ``DatabaseOperations.datetime_cast_sql()`` method (not to be confused
with ``DatabaseOperations.datetime_cast_date_sql()`` mentioned above) with ``DatabaseOperations.datetime_cast_date_sql()`` mentioned above)
has been removed. This method served to format dates on Oracle long has been removed. This method served to format dates on Oracle long
@ -822,6 +827,10 @@ Miscellaneous
be serialized contains any control characters not allowed in the XML 1.0 be serialized contains any control characters not allowed in the XML 1.0
standard, the serialization will fail with a :exc:`ValueError`. standard, the serialization will fail with a :exc:`ValueError`.
* :class:`~django.forms.CharField` now strips input of leading and trailing
whitespace by default. This can be disabled by setting the new
:attr:`~django.forms.CharField.strip` argument to ``False``.
.. _deprecated-features-1.9: .. _deprecated-features-1.9:
Features deprecated in 1.9 Features deprecated in 1.9

View File

@ -164,6 +164,18 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.widget_attrs(PasswordInput()), {'maxlength': '10'}) self.assertEqual(f.widget_attrs(PasswordInput()), {'maxlength': '10'})
self.assertEqual(f.widget_attrs(Textarea()), {'maxlength': '10'}) self.assertEqual(f.widget_attrs(Textarea()), {'maxlength': '10'})
def test_charfield_strip(self):
"""
Ensure that values have whitespace stripped and that strip=False works.
"""
f = CharField()
self.assertEqual(f.clean(' 1'), '1')
self.assertEqual(f.clean('1 '), '1')
f = CharField(strip=False)
self.assertEqual(f.clean(' 1'), ' 1')
self.assertEqual(f.clean('1 '), '1 ')
# IntegerField ################################################################ # IntegerField ################################################################
def test_integerfield_1(self): def test_integerfield_1(self):