Fixed #11185 - Expanded docs on customizing widgets; thanks fadeev for the draft patch.
This commit is contained in:
parent
65793d714c
commit
a73838fde3
|
@ -852,7 +852,7 @@ Slightly complex built-in ``Field`` classes
|
|||
``MultiValueField``
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. class:: MultiValueField(**kwargs)
|
||||
.. class:: MultiValueField(fields=(), **kwargs)
|
||||
|
||||
* Default widget: ``TextInput``
|
||||
* Empty value: ``''`` (an empty string)
|
||||
|
@ -861,22 +861,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``
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -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.
|
||||
|
||||
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.
|
||||
There are two ways to customize widgets: :ref:`per widget instance
|
||||
<styling-widget-instances>` and :ref:`per widget class <styling-widget-classes>`.
|
||||
|
||||
.. _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::
|
||||
|
||||
|
@ -128,9 +146,7 @@ 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. It is also possible to specify
|
||||
the 'type' attribute to take advantage of the new HTML5 input types. To do
|
||||
this, you use the :attr:`Widget.attrs` argument when creating the widget:
|
||||
|
||||
For example::
|
||||
this, you use the :attr:`Widget.attrs` argument when creating the widget::
|
||||
|
||||
class CommentForm(forms.Form):
|
||||
name = forms.CharField(
|
||||
|
@ -147,24 +163,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.
|
||||
|
||||
.. class:: Widget
|
||||
These methods involve somewhat advanced Python programming and are described in
|
||||
detail in the :doc:`Form Media </topics/forms/media>` topic guide.
|
||||
|
||||
This abstract class cannot be rendered, but provides the basic attribute :attr:`~Widget.attrs`.
|
||||
.. _base-widget-classes:
|
||||
|
||||
Base Widget classes
|
||||
-------------------
|
||||
|
||||
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.
|
||||
|
||||
.. 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
|
||||
|
||||
|
@ -172,6 +205,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``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
@ -205,39 +306,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``
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -297,6 +367,11 @@ commonly used groups of widgets:
|
|||
|
||||
Text area: ``<textarea>...</textarea>``
|
||||
|
||||
.. _selector-widgets:
|
||||
|
||||
Selector and checkbox widgets
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``CheckboxInput``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -440,6 +515,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``
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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://static.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
|
||||
|
|
Loading…
Reference in New Issue