A widget is Django’s representation of a HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget.
Whenever you specify a field on a form, Django will use a default widget that is appropriate to the type of data that is to be displayed. To find which widget is used on which field, see the documentation about Built-in Field classes.
However, if you want to use a different widget for a field, you can
just use the widget
argument on the field definition. For
example:
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField(widget=forms.Textarea)
This would specify a form with a comment that uses a larger Textarea
widget, rather than the default TextInput
widget.
Many widgets have optional extra arguments; they can be set when defining the
widget on the field. In the following example, the
years
attribute is set for a
SelectDateWidget
:
from django.forms.fields import DateField, ChoiceField, MultipleChoiceField
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.extras.widgets import SelectDateWidget
BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'))
FAVORITE_COLORS_CHOICES = (('blue', 'Blue'),
('green', 'Green'),
('black', 'Black'))
class SimpleForm(forms.Form):
birth_year = DateField(widget=SelectDateWidget(years=BIRTH_YEAR_CHOICES))
gender = ChoiceField(widget=RadioSelect, choices=GENDER_CHOICES)
favorite_colors = forms.MultipleChoiceField(required=False,
widget=CheckboxSelectMultiple, choices=FAVORITE_COLORS_CHOICES)
See the Built-in widgets for more information about which widgets are available and which arguments they accept.
Widgets inheriting from the Select
widget deal with choices. They
present the user with a list of options to choose from. The different widgets
present this choice differently; the Select
widget itself uses a
<select>
HTML list representation, while RadioSelect
uses radio
buttons.
Select
widgets are used by default on ChoiceField
fields. The
choices displayed on the widget are inherited from the ChoiceField
and
changing ChoiceField.choices
will update Select.choices
. For
example:
>>> from django import forms
>>> CHOICES = (('1', 'First',), ('2', 'Second',)))
>>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
>>> choice_field.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices = ()
>>> choice_field.choices = (('1', 'First and only',),)
>>> choice_field.widget.choices
[('1', 'First and only')]
Widgets which offer a choices
attribute can however be used
with fields which are not based on choice – such as a CharField
–
but it is recommended to use a ChoiceField
-based field when the
choices are inherent to the model and not just the representational widget.
When Django renders a widget as HTML, it only renders the bare minimum
HTML - Django doesn’t add a class definition, or any other widget-specific
attributes. This means that all TextInput
widgets will appear the same
on your Web page.
If you want to make one widget look different to another, you need to specify additional attributes for each widget. When you specify a widget, you can provide a list of attributes that will be added to the rendered HTML for the widget.
For example, take the following simple form:
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField()
This form will include three default TextInput
widgets, with default
rendering – no CSS class, no extra attributes. This means that the input boxes
provided for each widget will be rendered exactly the same:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
On a real Web page, you probably don’t want every widget to look the same. You
might want a larger input element for the comment, and you might want the
‘name’ widget to have some special CSS class. To do this, you use the
Widget.attrs
argument when creating the widget:
For example:
class CommentForm(forms.Form):
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
url = forms.URLField()
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
Django will then include the extra attributes in the rendered output:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
Django provides a representation of all the basic HTML widgets, plus some commonly used groups of widgets:
Widget
¶Widget
¶This abstract class cannot be rendered, but provides the basic attribute attrs
.
attrs
¶A dictionary containing HTML attributes to be set on the rendered widget.
>>> name = forms.TextInput(attrs={'size': 10, 'title': 'Your name',})
>>> name.render('name', 'A name')
u'<input title="Your name" type="text" name="name" value="A name" size="10" />'
PasswordInput
¶ClearableFileInput
¶ClearableFileInput
¶File upload input: <input type='file' ...>
, with an additional checkbox
input to clear the field’s value, if the field is not required and has
initial data.
DateInput
¶DateInput
¶Date input as a simple text box: <input type='text' ...>
Takes one optional argument:
format
¶The format in which this field’s initial value will be displayed.
If no format
argument is provided, the default format is the first
format found in DATE_INPUT_FORMATS
and respects
Format localization.
DateTimeInput
¶DateTimeInput
¶Date/time input as a simple text box: <input type='text' ...>
Takes one optional argument:
format
¶The format in which this field’s initial value will be displayed.
If no format
argument is provided, the default format is the first
format found in DATETIME_INPUT_FORMATS
and respects
Format localization.
TimeInput
¶TimeInput
¶Time input as a simple text box: <input type='text' ...>
Takes one optional argument:
format
¶The format in which this field’s initial value will be displayed.
If no format
argument is provided, the default format is the first
format found in TIME_INPUT_FORMATS
and respects
Format localization.
CheckboxInput
¶Select
¶SelectMultiple
¶RadioSelect
¶RadioSelect
¶Similar to Select
, but rendered as a list of radio buttons within
<li>
tags:
<ul>
<li><input type='radio' ...></li>
...
</ul>
For more granular control over the generated markup, you can loop over the
radio buttons in the template. Assuming a form myform
with a field
beatles
that uses a RadioSelect
as its widget:
{% for radio in myform.beatles %}
<div class="myradio">
{{ radio }}
</div>
{% endfor %}
This would generate the following HTML:
<div class="myradio">
<label><input type="radio" name="beatles" value="john" /> John</label>
</div>
<div class="myradio">
<label><input type="radio" name="beatles" value="paul" /> Paul</label>
</div>
<div class="myradio">
<label><input type="radio" name="beatles" value="george" /> George</label>
</div>
<div class="myradio">
<label><input type="radio" name="beatles" value="ringo" /> Ringo</label>
</div>
That included the <label>
tags. To get more granular, you can use each
radio button’s tag
and choice_label
attributes. For example, this template...
{% for radio in myform.beatles %}
<label>
{{ radio.choice_label }}
<span class="radio">{{ radio.tag }}</span>
</label>
{% endfor %}
...will result in the following HTML:
<label>
John
<span class="radio"><input type="radio" name="beatles" value="john" /></span>
</label>
<label>
Paul
<span class="radio"><input type="radio" name="beatles" value="paul" /></span>
</label>
<label>
George
<span class="radio"><input type="radio" name="beatles" value="george" /></span>
</label>
<label>
Ringo
<span class="radio"><input type="radio" name="beatles" value="ringo" /></span>
</label>
If you decide not to loop over the radio buttons – e.g., if your template simply includes
{{ myform.beatles }}
– they’ll be output in a <ul>
with <li>
tags, as above.
CheckboxSelectMultiple
¶CheckboxSelectMultiple
¶Similar to SelectMultiple
, but rendered as a list of check
buttons:
<ul>
<li><input type='checkbox' ...></li>
...
</ul>
MultiWidget
¶MultiWidget
¶Wrapper around multiple other widgets. You’ll probably want to use this
class with MultiValueField
.
Its render()
method is different than other widgets’, because it has to
figure out how to split a single value for display in multiple widgets.
Subclasses may implement format_output
, which takes the list of
rendered widgets and returns a string of HTML that formats them any way
you’d like.
The value
argument used when rendering can be one of two things:
list
.list
of values.In the second case – i.e., if the value is not a list – render()
will first decompress the value into a list
before rendering it. It
does so by calling the decompress()
method, which
MultiWidget
‘s subclasses must implement. This method takes a
single “compressed” value and returns a list
. An example of this is how
SplitDateTimeWidget
turns a datetime
value into a list
with date and time split into two seperate values:
class SplitDateTimeWidget(MultiWidget):
# ...
def decompress(self, value):
if value:
return [value.date(), value.time().replace(microsecond=0)]
return [None, None]
When render()
executes its HTML rendering, each value in the list is
rendered with the corresponding widget – the first value is rendered in
the first widget, the second value is rendered in the second widget, etc.
MultiWidget
has one required argument:
widgets
¶An iterable containing the widgets needed.
SplitDateTimeWidget
¶SplitDateTimeWidget
¶Wrapper (using MultiWidget
) around two widgets: DateInput
for the date, and TimeInput
for the time.
SplitDateTimeWidget
has two optional attributes:
date_format
¶Similar to DateInput.format
time_format
¶Similar to TimeInput.format
SelectDateWidget
¶SelectDateWidget
¶Wrapper around three Select
widgets: one each for
month, day, and year. Note that this widget lives in a separate file from
the standard widgets.
Takes one optional argument:
years
¶An optional list/tuple of years to use in the “year” select box. The default is a list containing the current year and the next 9 years.
Sep 27, 2017