diff options
| author | Jannis Leidel <jannis@leidel.info> | 2011-06-16 15:27:19 +0000 |
|---|---|---|
| committer | Jannis Leidel <jannis@leidel.info> | 2011-06-16 15:27:19 +0000 |
| commit | 662b372d022d0f638e62a3d4e3118f00a4fcce3d (patch) | |
| tree | ab7ff7310e0df3e813739474155b08f90d76abda /docs/ref | |
| parent | e008fde23e58a716804f0f5f334e3a44f2c170c6 (diff) | |
Fixed #16264 -- Improved form widget documentation. Many thanks to Bas Peschier.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16408 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs/ref')
| -rw-r--r-- | docs/ref/forms/fields.txt | 1 | ||||
| -rw-r--r-- | docs/ref/forms/widgets.txt | 354 |
2 files changed, 257 insertions, 98 deletions
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index 3fc5b8aabf..66c05e508e 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -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 -------------------------- diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index dbdf109134..13c0c88b6b 100644 --- a/docs/ref/forms/widgets.txt +++ b/docs/ref/forms/widgets.txt @@ -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. |
