| | 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 example: |
| | 24 | |
| | 25 | .. code-block:: python |
| | 26 | |
| | 27 | from django import forms |
| | 28 | |
| | 29 | class CommentForm(forms.Form): |
| | 30 | name = forms.CharField() |
| | 31 | url = forms.URLField() |
| | 32 | comment = forms.CharField(widget=forms.Textarea) |
| | 33 | |
| | 34 | This would specify a form with a comment that uses a larger Textarea widget, |
| | 35 | rather than the default TextInput widget. |
| | 36 | |
| | 37 | |
| | 38 | Setting arguments for widgets |
| | 39 | ----------------------------- |
| | 40 | |
| | 41 | Many widgets have optional extra arguments; they can be set when defining the |
| | 42 | widget on the field. In this example, the :attr:`~SelectDateWidget.years` |
| | 43 | attribute is set for a :class:`~django.forms.widgets.extras.SelectDateWidget`: |
| | 44 | |
| | 45 | .. code-block:: python |
| | 46 | |
| | 47 | from django import forms |
| | 48 | from django.forms.widgets.extras import SelectDateWidget |
| | 49 | |
| | 50 | YEAR_CHOICES = ('2010', '2009',) |
| | 51 | RADIO_CHOICES = (('1','Radio 1',), ('2','Radio 2',),) |
| | 52 | CHECKBOX_CHOICES = (('1','The first choice',), ('2','The Second Choice',),) |
| | 53 | |
| | 54 | class SimpleForm(forms.Form): |
| | 55 | year = forms.DateField(widget=SelectDateWidget(years=YEAR_CHOICES)) |
| | 56 | radio = forms.ChoiceField(widget=forms.RadioSelect, choices=RADIO_CHOICES) |
| | 57 | checkboxes = forms.MultipleChoiceField(required=False, |
| | 58 | widget=forms.CheckboxSelectMultiple, choices=CHECKBOX_CHOICES) |
| | 59 | |
| | 60 | The section :ref:`built-in widgets` contains information about which widgets are |
| | 61 | available and which arguments they accept. |
| | 62 | |
| | 63 | |
| | 64 | Widgets inheriting from the Select widget |
| | 65 | ----------------------------------------- |
| | 66 | |
| | 67 | Widgets inheriting from the :class:`Select` widget deal with choices. They present |
| | 68 | the user with a list of options to choose from. The different widgets present this |
| | 69 | choice differently; the :class:`Select` widget itself uses a ``<select>`` HTML |
| | 70 | list representation, while :class:`RadioSelect` uses radio buttons. |
| | 71 | |
| | 72 | :class:`Select` widgets are used by default on :class:`ChoiceField` fields. The |
| | 73 | choices displayed on the widget are inherited from the :class:`ChoiceField` and |
| | 74 | changing :attr:`ChoiceField.choices` will update :attr:`Select.choices`. For example: |
| | 75 | |
| | 76 | .. code-block:: python |
| | 77 | |
| | 78 | >>> from django import forms |
| | 79 | >>> CHOICES = (('1', 'First',), ('2', 'Second',))) |
| | 80 | >>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES) |
| | 81 | >>> choice_field.choices |
| | 82 | [('1', 'First'), ('2', 'Second')] |
| | 83 | >>> choice_field.widget.choices |
| | 84 | [('1', 'First'), ('2', 'Second')] |
| | 85 | >>> choice_field.widget.choices = () |
| | 86 | >>> choice_field.choices = (('1', 'First and only',),) |
| | 87 | >>> choice_field.widget.choices |
| | 88 | [('1', 'First and only')] |
| | 89 | |
| | 90 | |
| | 91 | Widgets which offer a :attr:`~Select.choices` attribute can however be used with |
| | 92 | fields which are not based on choice - such as a :class:`CharField` - but it is |
| | 93 | recommended to use a :class:`ChoiceField`-based field when the choices are |
| | 94 | inherent to the model and not just the representational widget. |
| | 95 | |
| | 96 | Customizing widget instances |
| | 97 | ---------------------------- |
| | 98 | |
| | 99 | When Django renders a widget as HTML, it only renders the bare minimum |
| | 100 | HTML - Django doesn't add a class definition, or any other widget-specific |
| | 101 | attributes. This means that all 'TextInput' widgets will appear the same |
| | 102 | on your Web page. |
| | 103 | |
| | 104 | If you want to make one widget look different to another, you need to |
| | 105 | specify additional attributes for each widget. When you specify a |
| | 106 | widget, you can provide a list of attributes that will be added to the |
| | 107 | rendered HTML for the widget. |
| | 108 | |
| | 109 | For example, take the following simple form: |
| | 110 | |
| | 111 | .. code-block:: python |
| | 112 | |
| | 113 | from django import forms |
| | 114 | |
| | 115 | class CommentForm(forms.Form): |
| | 116 | name = forms.CharField() |
| | 117 | url = forms.URLField() |
| | 118 | comment = forms.CharField() |
| | 119 | |
| | 120 | This form will include three default TextInput widgets, with default rendering - |
| | 121 | no CSS class, no extra attributes. This means that the input boxes provided for |
| | 122 | each widget will be rendered exactly the same: |
| | 123 | |
| | 124 | .. code-block:: python |
| | 125 | |
| | 126 | >>> f = CommentForm(auto_id=False) |
| | 127 | >>> f.as_table() |
| | 128 | <tr><th>Name:</th><td><input type="text" name="name" /></td></tr> |
| | 129 | <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> |
| | 130 | <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> |
| | 131 | |
| | 132 | |
| | 133 | On a real Web page, you probably don't want every widget to look the same. You |
| | 134 | might want a larger input element for the comment, and you might want the 'name' |
| | 135 | widget to have some special CSS class. To do this, you use the :attr:`Widget.attrs` |
| | 136 | argument when creating the widget: |
| | 137 | |
| | 138 | For example: |
| | 139 | |
| | 140 | .. code-block:: python |
| | 141 | |
| | 142 | class CommentForm(forms.Form): |
| | 143 | name = forms.CharField( |
| | 144 | widget=forms.TextInput(attrs={'class':'special'})) |
| | 145 | url = forms.URLField() |
| | 146 | comment = forms.CharField( |
| | 147 | widget=forms.TextInput(attrs={'size':'40'})) |
| | 148 | |
| | 149 | Django will then include the extra attributes in the rendered output: |
| | 150 | |
| | 151 | .. code-block:: python |
| | 152 | |
| | 153 | >>> f = CommentForm(auto_id=False) |
| | 154 | >>> f.as_table() |
| | 155 | <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr> |
| | 156 | <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> |
| | 157 | <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr> |
| | 158 | |
| | 159 | .. _built-in widgets: |
| | 160 | |
| | 161 | Built-in widgets |
| | 162 | ---------------- |
| | 163 | |
| 153 | | Wrapper around multiple other widgets |
| | 331 | Wrapper around multiple other widgets. You'll probably want to use this class |
| | 332 | with :class:`MultiValueField`. |
| | 333 | |
| | 334 | Its ``render`` method is different than other widgets', because it has to |
| | 335 | figure out how to split a single value for display in multiple widgets. |
| | 336 | |
| | 337 | Subclasses may implement ``format_output``, which takes the list of rendered |
| | 338 | widgets and returns a string of HTML that formats them any way you'd like. |
| | 339 | |
| | 340 | The ``value`` argument used when rendering can be one of two things: |
| | 341 | |
| | 342 | * A list. |
| | 343 | * A normal value (e.g., a string) that has been "compressed" from |
| | 344 | a list of values. |
| | 345 | |
| | 346 | In the second case - i.e., if the value is NOT a list - ``render`` will |
| | 347 | first ``decompress`` the value into a list before rendering it. It does so by |
| | 348 | calling the ``decompress`` method, which :class:`MultiWidget` subclasses must |
| | 349 | implement. This method takes a single "compressed" value and returns a |
| | 350 | list. |
| | 351 | |
| | 352 | An example of this is how :class:`SplitDateTimeWidget` turns a :class:`datetime` |
| | 353 | value into a list with date and time split into two seperate values: |
| | 354 | |
| | 355 | .. code-block:: python |
| | 356 | |
| | 357 | class SplitDateTimeWidget(MultiWidget): |
| | 358 | |
| | 359 | # ... |
| | 360 | |
| | 361 | def decompress(self, value): |
| | 362 | if value: |
| | 363 | return [value.date(), value.time().replace(microsecond=0)] |
| | 364 | return [None, None] |
| | 365 | |
| | 366 | When ``render`` does its HTML rendering, each value in the list is rendered |
| | 367 | with the corresponding widget - the first value is rendered in the first |
| | 368 | widget, the second value is rendered in the second widget, etc. |
| | 369 | |
| | 370 | :class:`MultiWidget` has one required argument: |
| | 371 | |
| | 372 | .. attribute:: MultiWidget.widgets |
| | 373 | |
| | 374 | An iterable containing the widgets needed. |
| 176 | | |
| 177 | | .. code-block:: python |
| 178 | | |
| 179 | | from django.forms.extras.widgets import SelectDateWidget |
| 180 | | |
| 181 | | date = forms.DateField(widget=SelectDateWidget()) |
| 182 | | |
| 183 | | Specifying widgets |
| 184 | | ------------------ |
| 185 | | .. currentmodule:: django.forms |
| 186 | | |
| 187 | | .. attribute:: Form.widget |
| 188 | | |
| 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. |
| 193 | | |
| 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:: |
| 196 | | |
| 197 | | from django import forms |
| 198 | | |
| 199 | | class CommentForm(forms.Form): |
| 200 | | name = forms.CharField() |
| 201 | | url = forms.URLField() |
| 202 | | comment = forms.CharField(widget=forms.Textarea) |
| 203 | | |
| 204 | | This would specify a form with a comment that uses a larger Textarea widget, |
| 205 | | rather than the default TextInput widget. |
| 206 | | |
| 207 | | Customizing widget instances |
| 208 | | ---------------------------- |
| 209 | | |
| 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. |
| 214 | | |
| 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. |
| 219 | | |
| 220 | | For example, take the following simple form:: |
| 221 | | |
| 222 | | class CommentForm(forms.Form): |
| 223 | | name = forms.CharField() |
| 224 | | url = forms.URLField() |
| 225 | | comment = forms.CharField() |
| 226 | | |
| 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 | | |
| 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> |
| 236 | | |
| 237 | | |
| 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: |
| 242 | | |
| 243 | | .. attribute:: Widget.attrs |
| 244 | | |
| 245 | | For example:: |
| 246 | | |
| 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'})) |
| 253 | | |
| 254 | | Django will then include the extra attributes in the rendered output:: |
| 255 | | |
| 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> |