Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ticket 16304 -- Add HTML5 placeholder attribute support to form fields #1111

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 7 additions & 3 deletions django/forms/fields.py
Expand Up @@ -20,7 +20,7 @@
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.forms.util import ErrorList, from_current_timezone, to_current_timezone from django.forms.util import ErrorList, from_current_timezone, to_current_timezone
from django.forms.widgets import ( from django.forms.widgets import (
TextInput, NumberInput, EmailInput, URLInput, HiddenInput, Input, Textarea, TextInput, NumberInput, EmailInput, URLInput, HiddenInput,
MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select,
NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION
Expand Down Expand Up @@ -199,8 +199,10 @@ def __deepcopy__(self, memo):
return result return result


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, placeholder=None,
self.max_length, self.min_length = max_length, min_length *args, **kwargs):
self.max_length, self.min_length, self.placeholder = (
max_length, min_length, placeholder)
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(min_length)) self.validators.append(validators.MinLengthValidator(min_length))
Expand All @@ -218,6 +220,8 @@ def widget_attrs(self, widget):
if self.max_length is not None and isinstance(widget, TextInput): if self.max_length is not None and isinstance(widget, TextInput):
# The HTML attribute is maxlength, not max_length. # The HTML attribute is maxlength, not max_length.
attrs.update({'maxlength': str(self.max_length)}) attrs.update({'maxlength': str(self.max_length)})
if self.placeholder and isinstance(widget, (Input, Textarea)):
attrs.update({'placeholder': self.placeholder})
return attrs return attrs


class IntegerField(Field): class IntegerField(Field):
Expand Down
8 changes: 5 additions & 3 deletions docs/ref/forms/fields.txt
Expand Up @@ -318,13 +318,15 @@ 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:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, placeholder is not meant for use in validation in any way.



.. attribute:: max_length .. attribute:: max_length
.. attribute:: min_length .. attribute:: min_length
.. attribute:: placeholder


If provided, these arguments ensure that the string is at most or at least If provided, max_length and min_length ensure that the string is at most or at least
the given length. 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`` ``ChoiceField``
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
Expand Down
10 changes: 10 additions & 0 deletions tests/forms_tests/tests/test_fields.py
Expand Up @@ -125,6 +125,16 @@ def test_charfield_5(self):
self.assertEqual(f.max_length, None) self.assertEqual(f.max_length, None)
self.assertEqual(f.min_length, 10) 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): def test_charfield_widget_attrs(self):
""" """
Ensure that CharField.widget_attrs() always returns a dictionary. Ensure that CharField.widget_attrs() always returns a dictionary.
Expand Down