Code

Ticket #16264: django-16264.5.diff

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