Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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 authored June 16, 2011
1  docs/ref/forms/fields.txt
@@ -278,6 +278,7 @@ as the rendered output.
278 278
 See the :ref:`format localization <format-localization>` documentation for
279 279
 more information.
280 280
 
  281
+.. _built-in fields:
281 282
 
282 283
 Built-in ``Field`` classes
283 284
 --------------------------
354  docs/ref/forms/widgets.txt
@@ -11,9 +11,181 @@ A widget is Django's representation of a HTML input element. The widget
11 11
 handles the rendering of the HTML, and the extraction of data from a GET/POST
12 12
 dictionary that corresponds to the widget.
13 13
 
  14
+Specifying widgets
  15
+------------------
  16
+
  17
+Whenever you specify a field on a form, Django will use a default widget
  18
+that is appropriate to the type of data that is to be displayed. To find
  19
+which widget is used on which field, see the documentation about
  20
+:ref:`built-in fields`.
  21
+
  22
+However, if you want to use a different widget for a field, you can
  23
+just use the :attr:`~Field.widget` argument on the field definition. For
  24
+example:
  25
+
  26
+    .. code-block:: python
  27
+
  28
+        from django import forms
  29
+
  30
+        class CommentForm(forms.Form):
  31
+            name = forms.CharField()
  32
+            url = forms.URLField()
  33
+            comment = forms.CharField(widget=forms.Textarea)
  34
+
  35
+This would specify a form with a comment that uses a larger :class:`Textarea`
  36
+widget, rather than the default :class:`TextInput` widget.
  37
+
  38
+
  39
+Setting arguments for widgets
  40
+-----------------------------
  41
+
  42
+Many widgets have optional extra arguments; they can be set when defining the
  43
+widget on the field. In the following example, the
  44
+:attr:`~SelectDateWidget.years` attribute is set for a
  45
+:class:`~django.forms.widgets.extras.SelectDateWidget`:
  46
+
  47
+    .. code-block:: python
  48
+
  49
+        from django.forms.fields import DateField, ChoiceField, MultipleChoiceField
  50
+        from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
  51
+        from django.forms.widgets.extras import SelectDateWidget
  52
+
  53
+        BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
  54
+        GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'))
  55
+        FAVOURITE_COLORS_CHOICES = (('blue', 'Blue'),
  56
+                                    ('green', 'Green'),
  57
+                                    ('black', 'Black'))
  58
+
  59
+        class SimpleForm(forms.Form):
  60
+            birth_year = DateField(widget=SelectDateWidget(years=YEAR_CHOICES))
  61
+            gender = ChoiceField(widget=RadioSelect, choices=RADIO_CHOICES)
  62
+            favourite_colors = forms.MultipleChoiceField(required=False,
  63
+                widget=CheckboxSelectMultiple, choices=CHECKBOX_CHOICES)
  64
+
  65
+See the :ref:`built-in widgets` for more information about which widgets
  66
+are available and which arguments they accept.
  67
+
  68
+
  69
+Widgets inheriting from the Select widget
  70
+-----------------------------------------
  71
+
  72
+Widgets inheriting from the :class:`Select` widget deal with choices. They
  73
+present the user with a list of options to choose from. The different widgets
  74
+present this choice differently; the :class:`Select` widget itself uses a
  75
+``<select>`` HTML list representation, while :class:`RadioSelect` uses radio
  76
+buttons.
  77
+
  78
+:class:`Select` widgets are used by default on :class:`ChoiceField` fields. The
  79
+choices displayed on the widget are inherited from the :class:`ChoiceField` and
  80
+changing :attr:`ChoiceField.choices` will update :attr:`Select.choices`. For
  81
+example:
  82
+
  83
+    .. code-block:: python
  84
+
  85
+        >>> from django import forms
  86
+        >>> CHOICES = (('1', 'First',), ('2', 'Second',)))
  87
+        >>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
  88
+        >>> choice_field.choices
  89
+        [('1', 'First'), ('2', 'Second')]
  90
+        >>> choice_field.widget.choices
  91
+        [('1', 'First'), ('2', 'Second')]
  92
+        >>> choice_field.widget.choices = ()
  93
+        >>> choice_field.choices = (('1', 'First and only',),)
  94
+        >>> choice_field.widget.choices
  95
+        [('1', 'First and only')]
  96
+
  97
+
  98
+Widgets which offer a :attr:`~Select.choices` attribute can however be used
  99
+with fields which are not based on choice -- such as a :class:`CharField` --
  100
+but it is recommended to use a :class:`ChoiceField`-based field when the
  101
+choices are inherent to the model and not just the representational widget.
  102
+
  103
+Customizing widget instances
  104
+----------------------------
  105
+
  106
+When Django renders a widget as HTML, it only renders the bare minimum
  107
+HTML - Django doesn't add a class definition, or any other widget-specific
  108
+attributes. This means that all :class:`TextInput` widgets will appear the same
  109
+on your Web page.
  110
+
  111
+If you want to make one widget look different to another, you need to
  112
+specify additional attributes for each widget. When you specify a
  113
+widget, you can provide a list of attributes that will be added to the
  114
+rendered HTML for the widget.
  115
+
  116
+For example, take the following simple form:
  117
+
  118
+    .. code-block:: python
  119
+
  120
+        from django import forms
  121
+
  122
+        class CommentForm(forms.Form):
  123
+            name = forms.CharField()
  124
+            url = forms.URLField()
  125
+            comment = forms.CharField()
  126
+
  127
+This form will include three default :class:`TextInput` widgets, with default
  128
+rendering -- no CSS class, no extra attributes. This means that the input boxes
  129
+provided for each widget will be rendered exactly the same:
  130
+
  131
+    .. code-block:: python
  132
+
  133
+        >>> f = CommentForm(auto_id=False)
  134
+        >>> f.as_table()
  135
+        <tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
  136
+        <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
  137
+        <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
  138
+
  139
+
  140
+On a real Web page, you probably don't want every widget to look the same. You
  141
+might want a larger input element for the comment, and you might want the
  142
+'name' widget to have some special CSS class. To do this, you use the
  143
+:attr:`Widget.attrs` argument when creating the widget:
  144
+
  145
+For example:
  146
+
  147
+    .. code-block:: python
  148
+
  149
+        class CommentForm(forms.Form):
  150
+            name = forms.CharField(
  151
+                        widget=forms.TextInput(attrs={'class':'special'}))
  152
+            url = forms.URLField()
  153
+            comment = forms.CharField(
  154
+                       widget=forms.TextInput(attrs={'size':'40'}))
  155
+
  156
+Django will then include the extra attributes in the rendered output:
  157
+
  158
+    .. code-block:: python
  159
+
  160
+        >>> f = CommentForm(auto_id=False)
  161
+        >>> f.as_table()
  162
+        <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
  163
+        <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
  164
+        <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
  165
+
  166
+.. _built-in widgets:
  167
+
  168
+Built-in widgets
  169
+----------------
  170
+
14 171
 Django provides a representation of all the basic HTML widgets, plus some
15 172
 commonly used groups of widgets:
16 173
 
  174
+.. class:: Widget
  175
+
  176
+    This abstract class cannot be rendered, but provides the basic attribute :attr:`~Widget.attrs`.
  177
+
  178
+    .. attribute:: Widget.attrs
  179
+
  180
+        A dictionary containing HTML attributes to be set on the rendered widget.
  181
+
  182
+        .. code-block:: python
  183
+
  184
+            >>> name = forms.TextInput(attrs={'size': 10, 'title': 'Your name',})
  185
+            >>> name.render('name', 'A name')
  186
+            u'<input title="Your name" type="text" name="name" value="A name" size="10" />'
  187
+
  188
+
17 189
 .. class:: TextInput
18 190
 
19 191
     Text input: ``<input type='text' ...>``
@@ -29,10 +201,10 @@ commonly used groups of widgets:
29 201
         Determines whether the widget will have a value filled in when the
30 202
         form is re-displayed after a validation error (default is ``False``).
31 203
 
32  
-.. versionchanged:: 1.3
33  
-    The default value for
34  
-    :attr:`~PasswordInput.render_value` was
35  
-    changed from ``True`` to ``False``
  204
+        .. versionchanged:: 1.3
  205
+            The default value for
  206
+            :attr:`~PasswordInput.render_value` was
  207
+            changed from ``True`` to ``False``
36 208
 
37 209
 .. class:: HiddenInput
38 210
 
@@ -42,6 +214,15 @@ commonly used groups of widgets:
42 214
 
43 215
     Multiple ``<input type='hidden' ...>`` widgets.
44 216
 
  217
+    A widget that handles multiple hidden widgets for fields that have a list
  218
+    of values.
  219
+
  220
+    .. attribute:: MultipleHiddenInput.choices
  221
+
  222
+        This attribute is optional when the field does not have a
  223
+        :attr:`~Field.choices` attribute. If it does, it will override anything
  224
+        you set here when the attribute is updated on the :class:`Field`.
  225
+
45 226
 .. class:: FileInput
46 227
 
47 228
     File upload input: ``<input type='file' ...>``
@@ -64,7 +245,9 @@ commonly used groups of widgets:
64 245
 
65 246
         The format in which this field's initial value will be displayed.
66 247
 
67  
-    If no ``format`` argument is provided, the default format is ``'%Y-%m-%d'``.
  248
+    If no ``format`` argument is provided, the default format is the first
  249
+    format found in :setting:`DATE_INPUT_FORMATS` and respects
  250
+    :ref:`format-localization`.
68 251
 
69 252
 .. class:: DateTimeInput
70 253
 
@@ -76,8 +259,9 @@ commonly used groups of widgets:
76 259
 
77 260
         The format in which this field's initial value will be displayed.
78 261
 
79  
-    If no ``format`` argument is provided, the default format is ``'%Y-%m-%d
80  
-    %H:%M:%S'``.
  262
+    If no ``format`` argument is provided, the default format is the first
  263
+    format found in :setting:`DATETIME_INPUT_FORMATS` and respects
  264
+    :ref:`format-localization`.
81 265
 
82 266
 .. class:: TimeInput
83 267
 
@@ -89,7 +273,9 @@ commonly used groups of widgets:
89 273
 
90 274
         The format in which this field's initial value will be displayed.
91 275
 
92  
-    If no ``format`` argument is provided, the default format is ``'%H:%M:%S'``.
  276
+    If no ``format`` argument is provided, the default format is the first
  277
+    format found in :setting:`TIME_INPUT_FORMATS` and respects
  278
+    :ref:`format-localization`.
93 279
 
94 280
 .. class:: Textarea
95 281
 
@@ -103,15 +289,18 @@ commonly used groups of widgets:
103 289
 
104 290
     .. attribute:: CheckboxInput.check_test
105 291
 
106  
-        A callable that takes the value of the CheckBoxInput
107  
-        and returns ``True`` if the checkbox should be checked for
108  
-        that value.
  292
+        A callable that takes the value of the CheckBoxInput and returns
  293
+        ``True`` if the checkbox should be checked for that value.
109 294
 
110 295
 .. class:: Select
111 296
 
112 297
     Select widget: ``<select><option ...>...</select>``
113 298
 
114  
-    Requires that your field provides :attr:`~Field.choices`.
  299
+    .. attribute:: Select.choices
  300
+
  301
+        This attribute is optional when the field does not have a
  302
+        :attr:`~Field.choices` attribute. If it does, it will override anything
  303
+        you set here when the attribute is updated on the :class:`Field`.
115 304
 
116 305
 .. class:: NullBooleanSelect
117 306
 
@@ -119,14 +308,12 @@ commonly used groups of widgets:
119 308
 
120 309
 .. class:: SelectMultiple
121 310
 
122  
-    Select widget allowing multiple selection: ``<select
123  
-    multiple='multiple'>...</select>``
124  
-
125  
-    Requires that your field provides :attr:`~Field.choices`.
  311
+    Similar to :class:`Select`, but allows multiple selection:
  312
+    ``<select multiple='multiple'>...</select>``
126 313
 
127 314
 .. class:: RadioSelect
128 315
 
129  
-    A list of radio buttons:
  316
+    Similar to :class:`Select`, but rendered as a list of radio buttons:
130 317
 
131 318
     .. code-block:: html
132 319
 
@@ -135,11 +322,10 @@ commonly used groups of widgets:
135 322
           ...
136 323
         </ul>
137 324
 
138  
-    Requires that your field provides :attr:`~Field.choices`.
139  
-
140 325
 .. class:: CheckboxSelectMultiple
141 326
 
142  
-    A list of checkboxes:
  327
+    Similar to :class:`SelectMultiple`, but rendered as a list of check
  328
+    buttons:
143 329
 
144 330
     .. code-block:: html
145 331
 
@@ -150,111 +336,83 @@ commonly used groups of widgets:
150 336
 
151 337
 .. class:: MultiWidget
152 338
 
153  
-    Wrapper around multiple other widgets
  339
+    Wrapper around multiple other widgets. You'll probably want to use this
  340
+    class with :class:`MultiValueField`.
154 341
 
155  
-.. class:: SplitDateTimeWidget
156  
-
157  
-    Wrapper around two widgets: ``DateInput`` for the date, and ``TimeInput``
158  
-    for the time.
  342
+    Its ``render()`` method is different than other widgets', because it has to
  343
+    figure out how to split a single value for display in multiple widgets.
159 344
 
160  
-    Takes two optional arguments, ``date_format`` and ``time_format``, which
161  
-    work just like the ``format`` argument for ``DateInput`` and ``TimeInput``.
  345
+    Subclasses may implement ``format_output``, which takes the list of
  346
+    rendered widgets and returns a string of HTML that formats them any way
  347
+    you'd like.
162 348
 
163  
-.. currentmodule:: django.forms.extras.widgets
  349
+    The ``value`` argument used when rendering can be one of two things:
164 350
 
165  
-.. class:: SelectDateWidget
  351
+    * A ``list``.
  352
+    * A single value (e.g., a string) that is the "compressed" representation
  353
+      of a ``list`` of values.
166 354
 
167  
-    Wrapper around three select widgets: one each for month, day, and year.
168  
-    Note that this widget lives in a separate file from the standard widgets.
169  
-
170  
-    Takes one optional argument:
171  
-
172  
-    .. attribute:: List.years
173  
-
174  
-        An optional list/tuple of years to use in the "year" select box.
175  
-        The default is a list containing the current year and the next 9 years.
  355
+    In the second case -- i.e., if the value is *not* a list -- ``render()``
  356
+    will first decompress the value into a ``list`` before rendering it. It
  357
+    does so by calling the ``decompress()`` method, which
  358
+    :class:`MultiWidget`'s subclasses must implement. This method takes a
  359
+    single "compressed" value and returns a ``list``. An example of this is how
  360
+    :class:`SplitDateTimeWidget` turns a :class:`datetime` value into a list
  361
+    with date and time split into two seperate values:
176 362
 
177 363
     .. code-block:: python
178 364
 
179  
-        from django.forms.extras.widgets import SelectDateWidget
  365
+        class SplitDateTimeWidget(MultiWidget):
180 366
 
181  
-        date = forms.DateField(widget=SelectDateWidget())
  367
+            # ...
182 368
 
183  
-Specifying widgets
184  
-------------------
185  
-.. currentmodule:: django.forms
  369
+            def decompress(self, value):
  370
+                if value:
  371
+                    return [value.date(), value.time().replace(microsecond=0)]
  372
+                return [None, None]
186 373
 
187  
-.. attribute:: Form.widget
  374
+    When ``render()`` executes its HTML rendering, each value in the list is
  375
+    rendered with the corresponding widget -- the first value is rendered in
  376
+    the first widget, the second value is rendered in the second widget, etc.
188 377
 
189  
-Whenever you specify a field on a form, Django will use a default widget
190  
-that is appropriate to the type of data that is to be displayed. To find
191  
-which widget is used on which field, see the documentation for the
192  
-built-in Field classes.
  378
+    :class:`MultiWidget` has one required argument:
193 379
 
194  
-However, if you want to use a different widget for a field, you can -
195  
-just use the 'widget' argument on the field definition. For example::
  380
+    .. attribute:: MultiWidget.widgets
196 381
 
197  
-    from django import forms
  382
+        An iterable containing the widgets needed.
198 383
 
199  
-    class CommentForm(forms.Form):
200  
-        name = forms.CharField()
201  
-        url = forms.URLField()
202  
-        comment = forms.CharField(widget=forms.Textarea)
  384
+.. class:: SplitDateTimeWidget
203 385
 
204  
-This would specify a form with a comment that uses a larger Textarea widget,
205  
-rather than the default TextInput widget.
  386
+    Wrapper (using :class:`MultiWidget`) around two widgets: :class:`DateInput`
  387
+    for the date, and :class:`TimeInput` for the time.
206 388
 
207  
-Customizing widget instances
208  
-----------------------------
  389
+    ``SplitDateTimeWidget`` has two optional attributes:
209 390
 
210  
-When Django renders a widget as HTML, it only renders the bare minimum
211  
-HTML - Django doesn't add a class definition, or any other widget-specific
212  
-attributes. This means that all 'TextInput' widgets will appear the same
213  
-on your Web page.
  391
+    .. attribute:: SplitDateTimeWidget.date_format
214 392
 
215  
-If you want to make one widget look different to another, you need to
216  
-specify additional attributes for each widget. When you specify a
217  
-widget, you can provide a list of attributes that will be added to the
218  
-rendered HTML for the widget.
  393
+        Similar to :attr:`DateInput.format`
219 394
 
220  
-For example, take the following simple form::
  395
+    .. attribute:: SplitDateTimeWidget.time_format
221 396
 
222  
-    class CommentForm(forms.Form):
223  
-        name = forms.CharField()
224  
-        url = forms.URLField()
225  
-        comment = forms.CharField()
  397
+        Similar to :attr:`TimeInput.format`
226 398
 
227  
-This form will include three default TextInput widgets, with default rendering -
228  
-no CSS class, no extra attributes. This means that the input boxes provided for
229  
-each widget will be rendered exactly the same::
230 399
 
231  
-    >>> f = CommentForm(auto_id=False)
232  
-    >>> f.as_table()
233  
-    <tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
234  
-    <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
235  
-    <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
  400
+.. class:: SplitHiddenDateTimeWidget
236 401
 
  402
+    Similar to :class:`SplitDateTimeWidget`, but uses :class:`HiddenInput` for
  403
+    both date and time.
237 404
 
238  
-On a real Web page, you probably don't want every widget to look the same. You
239  
-might want a larger input element for the comment, and you might want the 'name'
240  
-widget to have some special CSS class. To do this, you use the ``attrs``
241  
-argument when creating the widget:
  405
+.. currentmodule:: django.forms.widgets.extras
242 406
 
243  
-.. attribute:: Widget.attrs
  407
+.. class:: SelectDateWidget
244 408
 
245  
-For example::
  409
+    Wrapper around three :class:`~django.forms.Select` widgets: one each for
  410
+    month, day, and year. Note that this widget lives in a separate file from
  411
+    the standard widgets.
246 412
 
247  
-    class CommentForm(forms.Form):
248  
-        name = forms.CharField(
249  
-                    widget=forms.TextInput(attrs={'class':'special'}))
250  
-        url = forms.URLField()
251  
-        comment = forms.CharField(
252  
-                   widget=forms.TextInput(attrs={'size':'40'}))
  413
+    Takes one optional argument:
253 414
 
254  
-Django will then include the extra attributes in the rendered output::
  415
+    .. attribute:: SelectDateWidget.years
255 416
 
256  
-    >>> f = CommentForm(auto_id=False)
257  
-    >>> f.as_table()
258  
-    <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
259  
-    <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
260  
-    <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
  417
+        An optional list/tuple of years to use in the "year" select box.
  418
+        The default is a list containing the current year and the next 9 years.

0 notes on commit 662b372

Please sign in to comment.
Something went wrong with that request. Please try again.