Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[1.4.x] Fixed #11185 - Expanded docs on customizing widgets; thanks f…

…adeev for the draft patch.

Backport of a73838f from master.
  • Loading branch information...
commit 1b5b8b874fb79a8d2b2bc7ca8f93535ff8196167 1 parent 7c66309
@timgraham timgraham authored
View
41 docs/ref/forms/fields.txt
@@ -861,7 +861,7 @@ Slightly complex built-in ``Field`` classes
``MultiValueField``
~~~~~~~~~~~~~~~~~~~
-.. class:: MultiValueField(**kwargs)
+.. class:: MultiValueField(fields=(), **kwargs)
* Default widget: ``TextInput``
* Empty value: ``''`` (an empty string)
@@ -870,22 +870,39 @@ Slightly complex built-in ``Field`` classes
as an argument to the ``MultiValueField``.
* Error message keys: ``required``, ``invalid``
- This abstract field (must be subclassed) aggregates the logic of multiple
- fields. Subclasses should not have to implement clean(). Instead, they must
- implement compress(), which takes a list of valid values and returns a
- "compressed" version of those values -- a single value. For example,
- :class:`SplitDateTimeField` is a subclass which combines a time field and
- a date field into a datetime object.
+ Aggregates the logic of multiple fields that together produce a single
+ value.
+
+ This field is abstract and must be subclassed. In contrast with the
+ single-value fields, subclasses of :class:`MultiValueField` must not
+ implement :meth:`~django.forms.Field.clean` but instead - implement
+ :meth:`~MultiValueField.compress`.
Takes one extra required argument:
.. attribute:: fields
- A list of fields which are cleaned into a single field. Each value in
- ``clean`` is cleaned by the corresponding field in ``fields`` -- the first
- value is cleaned by the first field, the second value is cleaned by
- the second field, etc. Once all fields are cleaned, the list of clean
- values is "compressed" into a single value.
+ A tuple of fields whose values are cleaned and subsequently combined
+ into a single value. Each value of the field is cleaned by the
+ corresponding field in ``fields`` -- the first value is cleaned by the
+ first field, the second value is cleaned by the second field, etc.
+ Once all fields are cleaned, the list of clean values is combined into
+ a single value by :meth:`~MultiValueField.compress`.
+
+ .. attribute:: MultiValueField.widget
+
+ Must be a subclass of :class:`django.forms.MultiWidget`.
+ Default value is :class:`~django.forms.widgets.TextInput`, which
+ probably is not very useful in this case.
+
+ .. method:: compress(data_list)
+
+ Takes a list of valid values and returns a "compressed" version of
+ those values -- in a single value. For example,
+ :class:`SplitDateTimeField` is a subclass which combines a time field
+ and a date field into a ``datetime`` object.
+
+ This method must be implemented in the subclasses.
``SplitDateTimeField``
~~~~~~~~~~~~~~~~~~~~~~
View
227 docs/ref/forms/widgets.txt
@@ -11,6 +11,16 @@ 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.
+.. tip::
+
+ Widgets should not be confused with the :doc:`form fields </ref/forms/fields>`.
+ Form fields deal with the logic of input validation and are used directly
+ in templates. Widgets deal with rendering of HTML form input elements on
+ the web page and extraction of raw submitted data. However, widgets do
+ need to be :ref:`assigned <widget-to-field>` to form fields.
+
+.. _widget-to-field:
+
Specifying widgets
------------------
@@ -95,15 +105,23 @@ 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.
+When Django renders a widget as HTML, it only renders very minimal markup -
+Django doesn't add class names, or any other widget-specific attributes. This
+means, for example, that all :class:`TextInput` widgets will appear the same
+on your Web pages.
+
+There are two ways to customize widgets: :ref:`per widget instance
+<styling-widget-instances>` and :ref:`per widget class <styling-widget-classes>`.
-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.
+.. _styling-widget-instances:
+
+Styling widget instances
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you want to make one widget instance look different from another, you will
+need to specify additional attributes at the time when the widget object is
+instantiated and assigned to a form field (and perhaps add some rules to your
+CSS files).
For example, take the following simple form::
@@ -127,9 +145,7 @@ provided for each widget will be rendered exactly the same::
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::
+:attr:`Widget.attrs` argument when creating the widget::
class CommentForm(forms.Form):
name = forms.CharField(
@@ -146,24 +162,41 @@ Django will then include the extra attributes in the rendered output:
<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:
+.. _styling-widget-classes:
-Built-in widgets
-----------------
+Styling widget classes
+^^^^^^^^^^^^^^^^^^^^^^
-Django provides a representation of all the basic HTML widgets, plus some
-commonly used groups of widgets:
+With widgets, it is possible to add media (``css`` and ``javascript``)
+and more deeply customize their appearance and behavior.
-``Widget``
-~~~~~~~~~~
+In a nutshell, you will need to subclass the widget and either
+:ref:`define a class "Media" <media-as-a-static-definition>` as a member of the
+subclass, or :ref:`create a property "media" <dynamic-property>`, returning an
+instance of that class.
+
+These methods involve somewhat advanced Python programming and are described in
+detail in the :doc:`Form Media </topics/forms/media>` topic guide.
+
+.. _base-widget-classes:
+
+Base Widget classes
+-------------------
-.. class:: Widget
+Base widget classes :class:`Widget` and :class:`MultiWidget` are subclassed by
+all the :ref:`built-in widgets <built-in widgets>` and may serve as a
+foundation for custom widgets.
- This abstract class cannot be rendered, but provides the basic attribute :attr:`~Widget.attrs`.
+.. class:: Widget(attrs=None)
+
+ This abstract class cannot be rendered, but provides the basic attribute
+ :attr:`~Widget.attrs`. You may also implement or override the
+ :meth:`~Widget.render()` method on custom widgets.
.. attribute:: Widget.attrs
- A dictionary containing HTML attributes to be set on the rendered widget.
+ A dictionary containing HTML attributes to be set on the rendered
+ widget.
.. code-block:: python
@@ -171,6 +204,74 @@ commonly used groups of widgets:
>>> name.render('name', 'A name')
u'<input title="Your name" type="text" name="name" value="A name" size="10" />'
+ .. method:: render(name, value, attrs=None)
+
+ Returns HTML for the widget, as a Unicode string. This method must be
+ implemented by the subclass, otherwise ``NotImplementedError`` will be
+ raised.
+
+ The 'value' given is not guaranteed to be valid input, therefore
+ subclass implementations should program defensively.
+
+.. class:: MultiWidget(widgets, attrs=None)
+
+ A widget that is composed of multiple widgets.
+ :class:`~django.forms.widgets.MultiWidget` works hand in hand with the
+ :class:`~django.forms.MultiValueField`.
+
+ .. method:: render(name, value, attrs=None)
+
+ Argument `value` is handled differently in this method from the
+ subclasses of :class:`~Widget`.
+
+ If `value` is a list, output of :meth:`~MultiWidget.render` will be a
+ concatenation of rendered child widgets. If `value` is not a list, it
+ will be first processed by the method :meth:`~MultiWidget.decompress()`
+ to create the list and then processed as above.
+
+ Unlike in the single value widgets, method :meth:`~MultiWidget.render`
+ need not be implemented in the subclasses.
+
+ .. method:: decompress(value)
+
+ Returns a list of "decompressed" values for the given value of the
+ multi-value field that makes use of the widget. The input value can be
+ assumed as valid, but not necessarily non-empty.
+
+ This method **must be implemented** by the subclass, and since the
+ value may be empty, the implementation must be defensive.
+
+ The rationale behind "decompression" is that it is necessary to "split"
+ the combined value of the form field into the values of the individual
+ field encapsulated within the multi-value field (e.g. when displaying
+ the partially or fully filled-out form).
+
+ .. tip::
+
+ Note that :class:`~django.forms.MultiValueField` has a
+ complementary method :meth:`~django.forms.MultiValueField.compress`
+ with the opposite responsibility - to combine cleaned values of
+ all member fields into one.
+
+
+.. _built-in widgets:
+
+Built-in widgets
+----------------
+
+Django provides a representation of all the basic HTML widgets, plus some
+commonly used groups of widgets in the ``django.forms.widgets`` module,
+including :ref:`the input of text <text-widgets>`, :ref:`various checkboxes
+and selectors <selector-widgets>`, :ref:`uploading files <file-upload-widgets>`,
+and :ref:`handling of multi-valued input <composite-widgets>`.
+
+.. _text-widgets:
+
+Widgets handling input of text
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+These widgets make use of the HTML elements ``input`` and ``textarea``.
+
``TextInput``
~~~~~~~~~~~~~
@@ -204,39 +305,8 @@ commonly used groups of widgets:
Hidden input: ``<input type='hidden' ...>``
-``MultipleHiddenInput``
-~~~~~~~~~~~~~~~~~~~~~~~
-
-.. class:: MultipleHiddenInput
-
- 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`.
-
-``FileInput``
-~~~~~~~~~~~~~
-
-.. class:: FileInput
-
- File upload input: ``<input type='file' ...>``
-
-``ClearableFileInput``
-~~~~~~~~~~~~~~~~~~~~~~
-
-.. class:: ClearableFileInput
-
- .. versionadded:: 1.3
-
- File upload input: ``<input type='file' ...>``, with an additional checkbox
- input to clear the field's value, if the field is not required and has
- initial data.
+ Note that there also is a :class:`MultipleHiddenInput` widget that
+ encapsulates a set of hidden input elements.
``DateInput``
~~~~~~~~~~~~~
@@ -296,6 +366,11 @@ commonly used groups of widgets:
Text area: ``<textarea>...</textarea>``
+.. _selector-widgets:
+
+Selector and checkbox widgets
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
``CheckboxInput``
~~~~~~~~~~~~~~~~~
@@ -435,6 +510,50 @@ commonly used groups of widgets:
...
</ul>
+.. _file-upload-widgets:
+
+File upload widgets
+^^^^^^^^^^^^^^^^^^^
+
+``FileInput``
+~~~~~~~~~~~~~
+
+.. class:: FileInput
+
+ File upload input: ``<input type='file' ...>``
+
+``ClearableFileInput``
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: ClearableFileInput
+
+ .. versionadded:: 1.3
+
+ File upload input: ``<input type='file' ...>``, with an additional checkbox
+ input to clear the field's value, if the field is not required and has
+ initial data.
+
+.. _composite-widgets:
+
+Composite widgets
+^^^^^^^^^^^^^^^^^
+
+``MultipleHiddenInput``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: MultipleHiddenInput
+
+ 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`.
+
``MultiWidget``
~~~~~~~~~~~~~~~
View
24 docs/topics/forms/media.txt
@@ -38,6 +38,8 @@ in a form suitable for easy inclusion on your Web page.
whichever toolkit suits your requirements. Django is able to integrate
with any JavaScript toolkit.
+.. _media-as-a-static-definition:
+
Media as a static definition
----------------------------
@@ -78,10 +80,8 @@ A dictionary describing the CSS files required for various forms of output
media.
The values in the dictionary should be a tuple/list of file names. See
-`the section on media paths`_ for details of how to specify paths to media
-files.
-
-.. _the section on media paths: `Paths in media definitions`_
+:ref:`the section on media paths <form-media-paths>` for details of how to
+specify paths to media files.
The keys in the dictionary are the output media types. These are the same
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
``js``
~~~~~~
-A tuple describing the required JavaScript files. See
-`the section on media paths`_ for details of how to specify paths to media
+A tuple describing the required JavaScript files. See :ref:`the section on
+media paths <form-media-paths>` for details of how to specify paths to media
files.
``extend``
@@ -164,10 +164,10 @@ declaration to the media declaration::
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
If you require even more control over media inheritance, define your media
-using a `dynamic property`_. Dynamic properties give you complete control over
-which media files are inherited, and which are not.
+using a :ref:`dynamic property <dynamic-property>`. Dynamic properties give
+you complete control over which media files are inherited, and which are not.
-.. _dynamic property: `Media as a dynamic property`_
+.. _dynamic-property:
Media as a dynamic property
---------------------------
@@ -198,9 +198,9 @@ Paths in media definitions
.. versionchanged:: 1.3
Paths used to specify media can be either relative or absolute. If a path
-starts with '/', 'http://' or 'https://', it will be interpreted as an absolute
-path, and left as-is. All other paths will be prepended with the value of
-the appropriate prefix.
+starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an
+absolute path, and left as-is. All other paths will be prepended with the value
+of the appropriate prefix.
As part of the introduction of the
:doc:`staticfiles app </ref/contrib/staticfiles>` two new settings were added
Please sign in to comment.
Something went wrong with that request. Please try again.