diff --git a/django/forms/fields.py b/django/forms/fields.py index 4ce57d34a399c..6cbc59b8a3e59 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -20,7 +20,7 @@ from django.core.exceptions import ValidationError from django.forms.util import ErrorList, from_current_timezone, to_current_timezone from django.forms.widgets import ( - TextInput, NumberInput, EmailInput, URLInput, HiddenInput, + Input, Textarea, TextInput, NumberInput, EmailInput, URLInput, HiddenInput, MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION @@ -199,8 +199,10 @@ def __deepcopy__(self, memo): return result class CharField(Field): - def __init__(self, max_length=None, min_length=None, *args, **kwargs): - self.max_length, self.min_length = max_length, min_length + def __init__(self, max_length=None, min_length=None, placeholder=None, + *args, **kwargs): + self.max_length, self.min_length, self.placeholder = ( + max_length, min_length, placeholder) super(CharField, self).__init__(*args, **kwargs) if min_length is not None: self.validators.append(validators.MinLengthValidator(min_length)) @@ -218,6 +220,8 @@ def widget_attrs(self, widget): if self.max_length is not None and isinstance(widget, TextInput): # The HTML attribute is maxlength, not max_length. attrs.update({'maxlength': str(self.max_length)}) + if self.placeholder and isinstance(widget, (Input, Textarea)): + attrs.update({'placeholder': self.placeholder}) return attrs class IntegerField(Field): diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index 8e1a4b34d1ea5..6423c908ca340 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -318,13 +318,15 @@ For each field, we describe the default widget used if you don't specify Otherwise, all inputs are valid. * Error message keys: ``required``, ``max_length``, ``min_length`` - Has two optional arguments for validation: + Has three optional arguments for validation: .. attribute:: max_length .. attribute:: min_length + .. attribute:: placeholder - If provided, these arguments ensure that the string is at most or at least - the given length. + If provided, max_length and min_length ensure that the string is at most or at least + the given length. If provided, placeholder will show a placeholder attribute + in the html element, if it's an input box or a textarea. ``ChoiceField`` ~~~~~~~~~~~~~~~ diff --git a/tests/forms_tests/tests/test_fields.py b/tests/forms_tests/tests/test_fields.py index 7516de29b479c..d6b29fe522bd5 100644 --- a/tests/forms_tests/tests/test_fields.py +++ b/tests/forms_tests/tests/test_fields.py @@ -125,6 +125,16 @@ def test_charfield_5(self): self.assertEqual(f.max_length, None) self.assertEqual(f.min_length, 10) + def test_charfield_6(self): + f = CharField(placeholder='This is a random placeholder') + self.assertEqual('This is a random placeholder', f.placeholder) + self.assertEqual('This is a random placeholder', f.widget.attrs['placeholder']) + + def test_charfield_7(self): + f = CharField(placeholder='This is another placeholder', widget=Textarea) + self.assertEqual('This is another placeholder', f.placeholder) + self.assertEqual('This is another placeholder', f.widget.attrs['placeholder']) + def test_charfield_widget_attrs(self): """ Ensure that CharField.widget_attrs() always returns a dictionary.