Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #16264 -- Improved form widget documentation. Many thanks to Ba…

…s Peschier.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16408 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 662b372d022d0f638e62a3d4e3118f00a4fcce3d 1 parent e008fde
Jannis Leidel jezdez authored
Showing with 257 additions and 98 deletions.
  1. +1 −0  docs/ref/forms/fields.txt
  2. +256 −98 docs/ref/forms/widgets.txt
1  docs/ref/forms/fields.txt
View
@@ -278,6 +278,7 @@ as the rendered output.
See the :ref:`format localization <format-localization>` documentation for
more information.
+.. _built-in fields:
Built-in ``Field`` classes
--------------------------
354 docs/ref/forms/widgets.txt
View
@@ -11,9 +11,181 @@ 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.
+Specifying widgets
+------------------
+
+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
+:ref:`built-in fields`.
+
+However, if you want to use a different widget for a field, you can
+just use the :attr:`~Field.widget` argument on the field definition. For
+example:
+
+ .. code-block:: python
+
+ 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 :class:`Textarea`
+widget, rather than the default :class:`TextInput` widget.
+
+
+Setting arguments for widgets
+-----------------------------
+
+Many widgets have optional extra arguments; they can be set when defining the
+widget on the field. In the following example, the
+:attr:`~SelectDateWidget.years` attribute is set for a
+:class:`~django.forms.widgets.extras.SelectDateWidget`:
+
+ .. code-block:: python
+
+ from django.forms.fields import DateField, ChoiceField, MultipleChoiceField
+ from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
+ from django.forms.widgets.extras import SelectDateWidget
+
+ BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
+ GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'))
+ FAVOURITE_COLORS_CHOICES = (('blue', 'Blue'),
+ ('green', 'Green'),
+ ('black', 'Black'))
+
+ class SimpleForm(forms.Form):
+ birth_year = DateField(widget=SelectDateWidget(years=YEAR_CHOICES))
+ gender = ChoiceField(widget=RadioSelect, choices=RADIO_CHOICES)
+ favourite_colors = forms.MultipleChoiceField(required=False,
+ widget=CheckboxSelectMultiple, choices=CHECKBOX_CHOICES)
+
+See the :ref:`built-in widgets` for more information about which widgets
+are available and which arguments they accept.
+
+
+Widgets inheriting from the Select widget
+-----------------------------------------
+
+Widgets inheriting from the :class:`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 :class:`Select` widget itself uses a
+``<select>`` HTML list representation, while :class:`RadioSelect` uses radio
+buttons.
+
+:class:`Select` widgets are used by default on :class:`ChoiceField` fields. The
+choices displayed on the widget are inherited from the :class:`ChoiceField` and
+changing :attr:`ChoiceField.choices` will update :attr:`Select.choices`. For
+example:
+
+ .. code-block:: python
+
+ >>> 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 :attr:`~Select.choices` attribute can however be used
+with fields which are not based on choice -- such as a :class:`CharField` --
+but it is recommended to use a :class:`ChoiceField`-based field when the
+choices are inherent to the model and not just the representational widget.
+
+Customizing widget instances
+----------------------------
+
+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 :class:`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:
+
+ .. code-block:: python
+
+ from django import forms
+
+ class CommentForm(forms.Form):
+ name = forms.CharField()
+ url = forms.URLField()
+ comment = forms.CharField()
+
+This form will include three default :class:`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:
+
+ .. code-block:: python
+
+ >>> 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
+:attr:`Widget.attrs` argument when creating the widget:
+
+For example:
+
+ .. code-block:: python
+
+ 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:
+
+ .. code-block:: python
+
+ >>> 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>
+
+.. _built-in widgets:
+
+Built-in widgets
+----------------
+
Django provides a representation of all the basic HTML widgets, plus some
commonly used groups of widgets:
+.. class:: Widget
+
+ This abstract class cannot be rendered, but provides the basic attribute :attr:`~Widget.attrs`.
+
+ .. attribute:: Widget.attrs
+
+ A dictionary containing HTML attributes to be set on the rendered widget.
+
+ .. code-block:: python
+
+ >>> 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" />'
+
+
.. class:: TextInput
Text input: ``<input type='text' ...>``
@@ -29,10 +201,10 @@ commonly used groups of widgets:
Determines whether the widget will have a value filled in when the
form is re-displayed after a validation error (default is ``False``).
-.. versionchanged:: 1.3
- The default value for
- :attr:`~PasswordInput.render_value` was
- changed from ``True`` to ``False``
+ .. versionchanged:: 1.3
+ The default value for
+ :attr:`~PasswordInput.render_value` was
+ changed from ``True`` to ``False``
.. class:: HiddenInput
@@ -42,6 +214,15 @@ commonly used groups of widgets:
Multiple ``<input type='hidden' ...>`` widgets.
+ A widget that handles multiple hidden widgets for fields that have a list
+ of values.
+
+ .. attribute:: MultipleHiddenInput.choices
+
+ This attribute is optional when the field does not have a
+ :attr:`~Field.choices` attribute. If it does, it will override anything
+ you set here when the attribute is updated on the :class:`Field`.
+
.. class:: FileInput
File upload input: ``<input type='file' ...>``
@@ -64,7 +245,9 @@ commonly used groups of widgets:
The format in which this field's initial value will be displayed.
- If no ``format`` argument is provided, the default format is ``'%Y-%m-%d'``.
+ If no ``format`` argument is provided, the default format is the first
+ format found in :setting:`DATE_INPUT_FORMATS` and respects
+ :ref:`format-localization`.
.. class:: DateTimeInput
@@ -76,8 +259,9 @@ commonly used groups of widgets:
The format in which this field's initial value will be displayed.
- If no ``format`` argument is provided, the default format is ``'%Y-%m-%d
- %H:%M:%S'``.
+ If no ``format`` argument is provided, the default format is the first
+ format found in :setting:`DATETIME_INPUT_FORMATS` and respects
+ :ref:`format-localization`.
.. class:: TimeInput
@@ -89,7 +273,9 @@ commonly used groups of widgets:
The format in which this field's initial value will be displayed.
- If no ``format`` argument is provided, the default format is ``'%H:%M:%S'``.
+ If no ``format`` argument is provided, the default format is the first
+ format found in :setting:`TIME_INPUT_FORMATS` and respects
+ :ref:`format-localization`.
.. class:: Textarea
@@ -103,15 +289,18 @@ commonly used groups of widgets:
.. attribute:: CheckboxInput.check_test
- A callable that takes the value of the CheckBoxInput
- and returns ``True`` if the checkbox should be checked for
- that value.
+ A callable that takes the value of the CheckBoxInput and returns
+ ``True`` if the checkbox should be checked for that value.
.. class:: Select
Select widget: ``<select><option ...>...</select>``
- Requires that your field provides :attr:`~Field.choices`.
+ .. attribute:: Select.choices
+
+ This attribute is optional when the field does not have a
+ :attr:`~Field.choices` attribute. If it does, it will override anything
+ you set here when the attribute is updated on the :class:`Field`.
.. class:: NullBooleanSelect
@@ -119,14 +308,12 @@ commonly used groups of widgets:
.. class:: SelectMultiple
- Select widget allowing multiple selection: ``<select
- multiple='multiple'>...</select>``
-
- Requires that your field provides :attr:`~Field.choices`.
+ Similar to :class:`Select`, but allows multiple selection:
+ ``<select multiple='multiple'>...</select>``
.. class:: RadioSelect
- A list of radio buttons:
+ Similar to :class:`Select`, but rendered as a list of radio buttons:
.. code-block:: html
@@ -135,11 +322,10 @@ commonly used groups of widgets:
...
</ul>
- Requires that your field provides :attr:`~Field.choices`.
-
.. class:: CheckboxSelectMultiple
- A list of checkboxes:
+ Similar to :class:`SelectMultiple`, but rendered as a list of check
+ buttons:
.. code-block:: html
@@ -150,111 +336,83 @@ commonly used groups of widgets:
.. class:: MultiWidget
- Wrapper around multiple other widgets
+ Wrapper around multiple other widgets. You'll probably want to use this
+ class with :class:`MultiValueField`.
-.. class:: SplitDateTimeWidget
-
- Wrapper around two widgets: ``DateInput`` for the date, and ``TimeInput``
- for the time.
+ 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.
- Takes two optional arguments, ``date_format`` and ``time_format``, which
- work just like the ``format`` argument for ``DateInput`` and ``TimeInput``.
+ 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.
-.. currentmodule:: django.forms.extras.widgets
+ The ``value`` argument used when rendering can be one of two things:
-.. class:: SelectDateWidget
+ * A ``list``.
+ * A single value (e.g., a string) that is the "compressed" representation
+ of a ``list`` of values.
- 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:
-
- .. attribute:: List.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.
+ 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
+ :class:`MultiWidget`'s subclasses must implement. This method takes a
+ single "compressed" value and returns a ``list``. An example of this is how
+ :class:`SplitDateTimeWidget` turns a :class:`datetime` value into a list
+ with date and time split into two seperate values:
.. code-block:: python
- from django.forms.extras.widgets import SelectDateWidget
+ class SplitDateTimeWidget(MultiWidget):
- date = forms.DateField(widget=SelectDateWidget())
+ # ...
-Specifying widgets
-------------------
-.. currentmodule:: django.forms
+ def decompress(self, value):
+ if value:
+ return [value.date(), value.time().replace(microsecond=0)]
+ return [None, None]
-.. attribute:: Form.widget
+ 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.
-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 for the
-built-in Field classes.
+ :class:`MultiWidget` has one required argument:
-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::
+ .. attribute:: MultiWidget.widgets
- from django import forms
+ An iterable containing the widgets needed.
- class CommentForm(forms.Form):
- name = forms.CharField()
- url = forms.URLField()
- comment = forms.CharField(widget=forms.Textarea)
+.. class:: SplitDateTimeWidget
-This would specify a form with a comment that uses a larger Textarea widget,
-rather than the default TextInput widget.
+ Wrapper (using :class:`MultiWidget`) around two widgets: :class:`DateInput`
+ for the date, and :class:`TimeInput` for the time.
-Customizing widget instances
-----------------------------
+ ``SplitDateTimeWidget`` has two optional attributes:
-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.
+ .. attribute:: SplitDateTimeWidget.date_format
-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.
+ Similar to :attr:`DateInput.format`
-For example, take the following simple form::
+ .. attribute:: SplitDateTimeWidget.time_format
- class CommentForm(forms.Form):
- name = forms.CharField()
- url = forms.URLField()
- comment = forms.CharField()
+ Similar to :attr:`TimeInput.format`
-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>
+.. class:: SplitHiddenDateTimeWidget
+ Similar to :class:`SplitDateTimeWidget`, but uses :class:`HiddenInput` for
+ both date and time.
-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 ``attrs``
-argument when creating the widget:
+.. currentmodule:: django.forms.widgets.extras
-.. attribute:: Widget.attrs
+.. class:: SelectDateWidget
-For example::
+ Wrapper around three :class:`~django.forms.Select` widgets: one each for
+ month, day, and year. Note that this widget lives in a separate file from
+ the standard widgets.
- 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'}))
+ Takes one optional argument:
-Django will then include the extra attributes in the rendered output::
+ .. attribute:: SelectDateWidget.years
- >>> 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>
+ 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.
Please sign in to comment.
Something went wrong with that request. Please try again.