Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #11185 - Expanded docs on customizing widgets; thanks fadeev fo…

…r the draft patch.
  • Loading branch information...
commit a73838fde33374573b8e765dfcb0225287d396c0 1 parent 65793d7
Tim Graham authored September 12, 2012
41  docs/ref/forms/fields.txt
@@ -852,7 +852,7 @@ Slightly complex built-in ``Field`` classes
852 852
 ``MultiValueField``
853 853
 ~~~~~~~~~~~~~~~~~~~
854 854
 
855  
-.. class:: MultiValueField(**kwargs)
  855
+.. class:: MultiValueField(fields=(), **kwargs)
856 856
 
857 857
     * Default widget: ``TextInput``
858 858
     * Empty value: ``''`` (an empty string)
@@ -861,22 +861,39 @@ Slightly complex built-in ``Field`` classes
861 861
       as an argument to the ``MultiValueField``.
862 862
     * Error message keys: ``required``, ``invalid``
863 863
 
864  
-    This abstract field (must be subclassed) aggregates the logic of multiple
865  
-    fields. Subclasses should not have to implement clean(). Instead, they must
866  
-    implement compress(), which takes a list of valid values and returns a
867  
-    "compressed" version of those values -- a single value.  For example,
868  
-    :class:`SplitDateTimeField` is a subclass which combines a time field and
869  
-    a date field into a datetime object.
  864
+    Aggregates the logic of multiple fields that together produce a single
  865
+    value.
  866
+
  867
+    This field is abstract and must be subclassed. In contrast with the
  868
+    single-value fields, subclasses of :class:`MultiValueField` must not
  869
+    implement :meth:`~django.forms.Field.clean` but instead - implement
  870
+    :meth:`~MultiValueField.compress`.
870 871
 
871 872
     Takes one extra required argument:
872 873
 
873 874
     .. attribute:: fields
874 875
 
875  
-        A list of fields which are cleaned into a single field. Each value in
876  
-        ``clean`` is cleaned by the corresponding field in ``fields`` -- the first
877  
-        value is cleaned by the first field, the second value is cleaned by
878  
-        the second field, etc.  Once all fields are cleaned, the list of clean
879  
-        values is "compressed" into a single value.
  876
+        A tuple of fields whose values are cleaned and subsequently combined
  877
+        into a single value.  Each value of the field is cleaned by the
  878
+        corresponding field in ``fields`` -- the first value is cleaned by the
  879
+        first field, the second value is cleaned by the second field, etc.
  880
+        Once all fields are cleaned, the list of clean values is combined into
  881
+        a single value by :meth:`~MultiValueField.compress`.
  882
+
  883
+    .. attribute:: MultiValueField.widget
  884
+
  885
+        Must be a subclass of :class:`django.forms.MultiWidget`.
  886
+        Default value is :class:`~django.forms.widgets.TextInput`, which
  887
+        probably is not very useful in this case.
  888
+
  889
+    .. method:: compress(data_list)
  890
+
  891
+        Takes a list of valid values and returns  a "compressed" version of
  892
+        those values -- in a single value. For example,
  893
+        :class:`SplitDateTimeField` is a subclass which combines a time field
  894
+        and a date field into a ``datetime`` object.
  895
+
  896
+        This method must be implemented in the subclasses.
880 897
 
881 898
 ``SplitDateTimeField``
882 899
 ~~~~~~~~~~~~~~~~~~~~~~
227  docs/ref/forms/widgets.txt
@@ -11,6 +11,16 @@ 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
+.. tip::
  15
+
  16
+    Widgets should not be confused with the :doc:`form fields </ref/forms/fields>`.
  17
+    Form fields deal with the logic of input validation and are used directly
  18
+    in templates. Widgets deal with rendering of HTML form input elements on
  19
+    the web page and extraction of raw submitted data. However, widgets do
  20
+    need to be :ref:`assigned <widget-to-field>` to form fields.
  21
+
  22
+.. _widget-to-field:
  23
+
14 24
 Specifying widgets
15 25
 ------------------
16 26
 
@@ -95,15 +105,23 @@ choices are inherent to the model and not just the representational widget.
95 105
 Customizing widget instances
96 106
 ----------------------------
97 107
 
98  
-When Django renders a widget as HTML, it only renders the bare minimum
99  
-HTML - Django doesn't add a class definition, or any other widget-specific
100  
-attributes. This means that all :class:`TextInput` widgets will appear the same
101  
-on your Web page.
  108
+When Django renders a widget as HTML, it only renders very minimal markup -
  109
+Django doesn't add class names, or any other widget-specific attributes. This
  110
+means, for example, that all :class:`TextInput` widgets will appear the same
  111
+on your Web pages.
  112
+
  113
+There are two ways to customize widgets: :ref:`per widget instance
  114
+<styling-widget-instances>` and :ref:`per widget class <styling-widget-classes>`.
102 115
 
103  
-If you want to make one widget look different to another, you need to
104  
-specify additional attributes for each widget. When you specify a
105  
-widget, you can provide a list of attributes that will be added to the
106  
-rendered HTML for the widget.
  116
+.. _styling-widget-instances:
  117
+
  118
+Styling widget instances
  119
+^^^^^^^^^^^^^^^^^^^^^^^^
  120
+
  121
+If you want to make one widget instance look different from another, you will
  122
+need to specify additional attributes at the time when the widget object is
  123
+instantiated and assigned to a form field (and perhaps add some rules to your
  124
+CSS files).
107 125
 
108 126
 For example, take the following simple form::
109 127
 
@@ -128,9 +146,7 @@ On a real Web page, you probably don't want every widget to look the same. You
128 146
 might want a larger input element for the comment, and you might want the
129 147
 'name' widget to have some special CSS class. It is also possible to specify
130 148
 the 'type' attribute to take advantage of the new HTML5 input types.  To do
131  
-this, you use the :attr:`Widget.attrs` argument when creating the widget:
132  
-
133  
-For example::
  149
+this, you use the :attr:`Widget.attrs` argument when creating the widget::
134 150
 
135 151
     class CommentForm(forms.Form):
136 152
         name = forms.CharField(
@@ -147,24 +163,41 @@ Django will then include the extra attributes in the rendered output:
147 163
     <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
148 164
     <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
149 165
 
150  
-.. _built-in widgets:
  166
+.. _styling-widget-classes:
151 167
 
152  
-Built-in widgets
153  
-----------------
  168
+Styling widget classes
  169
+^^^^^^^^^^^^^^^^^^^^^^
154 170
 
155  
-Django provides a representation of all the basic HTML widgets, plus some
156  
-commonly used groups of widgets:
  171
+With widgets, it is possible to add media (``css`` and ``javascript``)
  172
+and more deeply customize their appearance and behavior.
157 173
 
158  
-``Widget``
159  
-~~~~~~~~~~
  174
+In a nutshell, you will need to subclass the widget and either
  175
+:ref:`define a class "Media" <media-as-a-static-definition>` as a member of the
  176
+subclass, or :ref:`create a property "media" <dynamic-property>`, returning an
  177
+instance of that class.
  178
+
  179
+These methods involve somewhat advanced Python programming and are described in
  180
+detail in the :doc:`Form Media </topics/forms/media>` topic guide.
  181
+
  182
+.. _base-widget-classes:
  183
+
  184
+Base Widget classes
  185
+-------------------
160 186
 
161  
-.. class:: Widget
  187
+Base widget classes :class:`Widget` and :class:`MultiWidget` are subclassed by
  188
+all the :ref:`built-in widgets <built-in widgets>` and may serve as a
  189
+foundation for custom widgets.
162 190
 
163  
-    This abstract class cannot be rendered, but provides the basic attribute :attr:`~Widget.attrs`.
  191
+.. class:: Widget(attrs=None)
  192
+
  193
+    This abstract class cannot be rendered, but provides the basic attribute
  194
+    :attr:`~Widget.attrs`.  You may also implement or override the
  195
+    :meth:`~Widget.render()` method on custom widgets.
164 196
 
165 197
     .. attribute:: Widget.attrs
166 198
 
167  
-        A dictionary containing HTML attributes to be set on the rendered widget.
  199
+        A dictionary containing HTML attributes to be set on the rendered
  200
+        widget.
168 201
 
169 202
         .. code-block:: python
170 203
 
@@ -172,6 +205,74 @@ commonly used groups of widgets:
172 205
             >>> name.render('name', 'A name')
173 206
             u'<input title="Your name" type="text" name="name" value="A name" size="10" />'
174 207
 
  208
+    .. method:: render(name, value, attrs=None)
  209
+
  210
+        Returns HTML for the widget, as a Unicode string. This method must be
  211
+        implemented by the subclass, otherwise ``NotImplementedError`` will be
  212
+        raised.
  213
+
  214
+        The 'value' given is not guaranteed to be valid input, therefore
  215
+        subclass implementations should program defensively.
  216
+
  217
+.. class:: MultiWidget(widgets, attrs=None)
  218
+
  219
+    A widget that is composed of multiple widgets.
  220
+    :class:`~django.forms.widgets.MultiWidget` works hand in hand with the
  221
+    :class:`~django.forms.MultiValueField`.
  222
+
  223
+    .. method:: render(name, value, attrs=None)
  224
+
  225
+        Argument `value` is handled differently in this method from the
  226
+        subclasses of :class:`~Widget`.
  227
+
  228
+        If `value` is a list, output of :meth:`~MultiWidget.render` will be a
  229
+        concatenation of rendered child widgets. If `value` is not a list, it
  230
+        will be first processed by the method :meth:`~MultiWidget.decompress()`
  231
+        to create the list and then processed as above.
  232
+
  233
+        Unlike in the single value widgets, method :meth:`~MultiWidget.render`
  234
+        need not be implemented in the subclasses.
  235
+
  236
+    .. method:: decompress(value)
  237
+
  238
+        Returns a list of "decompressed" values for the given value of the
  239
+        multi-value field that makes use of the widget. The input value can be
  240
+        assumed as valid, but not necessarily non-empty.
  241
+
  242
+        This method **must be implemented** by the subclass, and since the
  243
+        value may be empty, the implementation must be defensive.
  244
+
  245
+        The rationale behind "decompression" is that it is necessary to "split"
  246
+        the combined value of the form field into the values of the individual
  247
+        field encapsulated within the multi-value field (e.g. when displaying
  248
+        the partially or fully filled-out form).
  249
+
  250
+        .. tip::
  251
+
  252
+            Note that :class:`~django.forms.MultiValueField` has a
  253
+            complementary method :meth:`~django.forms.MultiValueField.compress`
  254
+            with the opposite responsibility - to combine cleaned values of
  255
+            all member fields into one.
  256
+
  257
+
  258
+.. _built-in widgets:
  259
+
  260
+Built-in widgets
  261
+----------------
  262
+
  263
+Django provides a representation of all the basic HTML widgets, plus some
  264
+commonly used groups of widgets in the ``django.forms.widgets`` module,
  265
+including :ref:`the input of text <text-widgets>`, :ref:`various checkboxes
  266
+and selectors <selector-widgets>`, :ref:`uploading files <file-upload-widgets>`,
  267
+and :ref:`handling of multi-valued input <composite-widgets>`.
  268
+
  269
+.. _text-widgets:
  270
+
  271
+Widgets handling input of text
  272
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  273
+
  274
+These widgets make use of the HTML elements ``input`` and ``textarea``.
  275
+
175 276
 ``TextInput``
176 277
 ~~~~~~~~~~~~~
177 278
 
@@ -205,39 +306,8 @@ commonly used groups of widgets:
205 306
 
206 307
     Hidden input: ``<input type='hidden' ...>``
207 308
 
208  
-``MultipleHiddenInput``
209  
-~~~~~~~~~~~~~~~~~~~~~~~
210  
-
211  
-.. class:: MultipleHiddenInput
212  
-
213  
-    Multiple ``<input type='hidden' ...>`` widgets.
214  
-
215  
-    A widget that handles multiple hidden widgets for fields that have a list
216  
-    of values.
217  
-
218  
-    .. attribute:: MultipleHiddenInput.choices
219  
-
220  
-        This attribute is optional when the field does not have a
221  
-        :attr:`~Field.choices` attribute. If it does, it will override anything
222  
-        you set here when the attribute is updated on the :class:`Field`.
223  
-
224  
-``FileInput``
225  
-~~~~~~~~~~~~~
226  
-
227  
-.. class:: FileInput
228  
-
229  
-    File upload input: ``<input type='file' ...>``
230  
-
231  
-``ClearableFileInput``
232  
-~~~~~~~~~~~~~~~~~~~~~~
233  
-
234  
-.. class:: ClearableFileInput
235  
-
236  
-    .. versionadded:: 1.3
237  
-
238  
-    File upload input: ``<input type='file' ...>``, with an additional checkbox
239  
-    input to clear the field's value, if the field is not required and has
240  
-    initial data.
  309
+    Note that there also is a :class:`MultipleHiddenInput` widget that
  310
+    encapsulates a set of hidden input elements.
241 311
 
242 312
 ``DateInput``
243 313
 ~~~~~~~~~~~~~
@@ -297,6 +367,11 @@ commonly used groups of widgets:
297 367
 
298 368
     Text area: ``<textarea>...</textarea>``
299 369
 
  370
+.. _selector-widgets:
  371
+
  372
+Selector and checkbox widgets
  373
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  374
+
300 375
 ``CheckboxInput``
301 376
 ~~~~~~~~~~~~~~~~~
302 377
 
@@ -440,6 +515,50 @@ commonly used groups of widgets:
440 515
           ...
441 516
         </ul>
442 517
 
  518
+.. _file-upload-widgets:
  519
+
  520
+File upload widgets
  521
+^^^^^^^^^^^^^^^^^^^
  522
+
  523
+``FileInput``
  524
+~~~~~~~~~~~~~
  525
+
  526
+.. class:: FileInput
  527
+
  528
+    File upload input: ``<input type='file' ...>``
  529
+
  530
+``ClearableFileInput``
  531
+~~~~~~~~~~~~~~~~~~~~~~
  532
+
  533
+.. class:: ClearableFileInput
  534
+
  535
+    .. versionadded:: 1.3
  536
+
  537
+    File upload input: ``<input type='file' ...>``, with an additional checkbox
  538
+    input to clear the field's value, if the field is not required and has
  539
+    initial data.
  540
+
  541
+.. _composite-widgets:
  542
+
  543
+Composite widgets
  544
+^^^^^^^^^^^^^^^^^
  545
+
  546
+``MultipleHiddenInput``
  547
+~~~~~~~~~~~~~~~~~~~~~~~
  548
+
  549
+.. class:: MultipleHiddenInput
  550
+
  551
+    Multiple ``<input type='hidden' ...>`` widgets.
  552
+
  553
+    A widget that handles multiple hidden widgets for fields that have a list
  554
+    of values.
  555
+
  556
+    .. attribute:: MultipleHiddenInput.choices
  557
+
  558
+        This attribute is optional when the field does not have a
  559
+        :attr:`~Field.choices` attribute. If it does, it will override anything
  560
+        you set here when the attribute is updated on the :class:`Field`.
  561
+
443 562
 ``MultiWidget``
444 563
 ~~~~~~~~~~~~~~~
445 564
 
24  docs/topics/forms/media.txt
@@ -38,6 +38,8 @@ in a form suitable for easy inclusion on your Web page.
38 38
     whichever toolkit suits your requirements. Django is able to integrate
39 39
     with any JavaScript toolkit.
40 40
 
  41
+.. _media-as-a-static-definition:
  42
+
41 43
 Media as a static definition
42 44
 ----------------------------
43 45
 
@@ -78,10 +80,8 @@ A dictionary describing the CSS files required for various forms of output
78 80
 media.
79 81
 
80 82
 The values in the dictionary should be a tuple/list of file names. See
81  
-`the section on media paths`_ for details of how to specify paths to media
82  
-files.
83  
-
84  
-.. _the section on media paths: `Paths in media definitions`_
  83
+:ref:`the section on media paths <form-media-paths>` for details of how to
  84
+specify paths to media files.
85 85
 
86 86
 The keys in the dictionary are the output media types. These are the same
87 87
 types accepted by CSS files in media declarations: 'all', 'aural', 'braille',
@@ -117,8 +117,8 @@ If this last CSS definition were to be rendered, it would become the following H
117 117
 ``js``
118 118
 ~~~~~~
119 119
 
120  
-A tuple describing the required JavaScript files. See
121  
-`the section on media paths`_ for details of how to specify paths to media
  120
+A tuple describing the required JavaScript files. See :ref:`the section on
  121
+media paths <form-media-paths>` for details of how to specify paths to media
122 122
 files.
123 123
 
124 124
 ``extend``
@@ -164,10 +164,10 @@ declaration to the media declaration::
164 164
     <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
165 165
 
166 166
 If you require even more control over media inheritance, define your media
167  
-using a `dynamic property`_. Dynamic properties give you complete control over
168  
-which media files are inherited, and which are not.
  167
+using a :ref:`dynamic property <dynamic-property>`. Dynamic properties give
  168
+you complete control over which media files are inherited, and which are not.
169 169
 
170  
-.. _dynamic property: `Media as a dynamic property`_
  170
+.. _dynamic-property:
171 171
 
172 172
 Media as a dynamic property
173 173
 ---------------------------
@@ -198,9 +198,9 @@ Paths in media definitions
198 198
 .. versionchanged:: 1.3
199 199
 
200 200
 Paths used to specify media can be either relative or absolute. If a path
201  
-starts with '/', 'http://' or 'https://', it will be interpreted as an absolute
202  
-path, and left as-is. All other paths will be prepended with the value of
203  
-the appropriate prefix.
  201
+starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an
  202
+absolute path, and left as-is. All other paths will be prepended with the value
  203
+of the appropriate prefix.
204 204
 
205 205
 As part of the introduction of the
206 206
 :doc:`staticfiles app </ref/contrib/staticfiles>` two new settings were added

0 notes on commit a73838f

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