diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index d83f781dc7..7ebd495924 100644 --- a/docs/ref/forms/fields.txt +++ b/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`` ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index fb7657349a..037efc8d39 100644 --- a/docs/ref/forms/widgets.txt +++ b/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 `. + 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 ` 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 +` and :ref:`per widget class `. + +.. _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: Url: Comment: -.. _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" ` as a member of the +subclass, or :ref:`create a property "media" `, 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 ` 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 ` 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 @@ -171,6 +204,74 @@ commonly used groups of widgets: >>> name.render('name', 'A name') u'' + .. 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 `, :ref:`various checkboxes +and selectors `, :ref:`uploading files `, +and :ref:`handling of multi-valued input `. + +.. _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: ```` -``MultipleHiddenInput`` -~~~~~~~~~~~~~~~~~~~~~~~ - -.. class:: MultipleHiddenInput - - Multiple ```` 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: ```` - -``ClearableFileInput`` -~~~~~~~~~~~~~~~~~~~~~~ - -.. class:: ClearableFileInput - - .. versionadded:: 1.3 - - File upload input: ````, 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: ```` +.. _selector-widgets: + +Selector and checkbox widgets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ``CheckboxInput`` ~~~~~~~~~~~~~~~~~ @@ -435,6 +510,50 @@ commonly used groups of widgets: ... +.. _file-upload-widgets: + +File upload widgets +^^^^^^^^^^^^^^^^^^^ + +``FileInput`` +~~~~~~~~~~~~~ + +.. class:: FileInput + + File upload input: ```` + +``ClearableFileInput`` +~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: ClearableFileInput + + .. versionadded:: 1.3 + + File upload input: ````, 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 ```` 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`` ~~~~~~~~~~~~~~~ diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt index 0eb3e91b3a..36783f1082 100644 --- a/docs/topics/forms/media.txt +++ b/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 ` 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 ` for details of how to specify paths to media files. ``extend`` @@ -164,10 +164,10 @@ declaration to the media declaration:: 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 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 ` two new settings were added