Ticket #11185: widget-evgeny1.diff

File widget-evgeny1.diff, 18.8 KB (added by fadeev, 8 years ago)

finished reference for creation of custom widgets, improved cross-linking between form-fields, widgets, and form media pages, changed link on main page from Built-in widgets to Widgets

  • django/forms/widgets.py

    diff --git a/django/forms/widgets.py b/django/forms/widgets.py
    index dd5868f..701fa79 100644
    a b class MediaDefiningClass(type): 
    136136        return new_class
    138138class Widget(object):
     139    """Base class for all :ref:`built-in widgets <builtin-widgets>`
     140    """
    139141    __metaclass__ = MediaDefiningClass
    140142    is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
    141143    needs_multipart_form = False # Determines does this widget need multipart-encrypted form
    class Widget(object): 
    157159    def render(self, name, value, attrs=None):
    158160        """
    159         Returns this Widget rendered as HTML, as a Unicode string.
     161        Returns HTML for the widget, as a Unicode string.
    161         The 'value' given is not guaranteed to be valid input, so subclass
    162         implementations should program defensively.
     163        The 'value' given is not guaranteed to be valid input,
     164        therefore subclass implementations should program defensively.
    163165        """
    164166        raise NotImplementedError
  • docs/index.txt

    diff --git a/docs/index.txt b/docs/index.txt
    index 0cf066e..ee7ab15 100644
    a b Forms 
    124124      :doc:`Overview <topics/forms/index>` |
    125125      :doc:`Form API <ref/forms/api>` |
    126126      :doc:`Built-in fields <ref/forms/fields>` |
    127       :doc:`Built-in widgets <ref/forms/widgets>`
     127      :doc:`Widgets <ref/forms/widgets>`
    129129    * **Advanced:**
    130130      :doc:`Forms for models <topics/forms/modelforms>` |
  • docs/ref/forms/fields.txt

    diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
    index b49864f..20ba4c7 100644
    a b as the rendered output. 
    278278See the :ref:`format localization <format-localization>` documentation for
    279279more information.
     281.. _builtin-form-fields:
    282283Built-in ``Field`` classes
    Takes one extra required argument: 
    797798        ...
    798799        ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
     801.. _multi-value-field:
    803 .. class:: MultiValueField(**kwargs)
     806.. class:: MultiValueField(fields = (), **kwargs)
     808    Aggregates the logic of multiple fields that together
     809    produce a single cleaned value.
     811    This field is abstract and must be subclassed.
     812    Also, in contrast with the single-value fields
     813    the subclasses of :class:`MultiValueField`
     814    must not implement :meth:`~forms.Field.clean`
     815    but
     816    instead - implement :meth:`~forms.MultiValueField.compress`.
    805     * Default widget: ``TextInput``
    806818    * Empty value: ``''`` (an empty string)
    807819    * Normalizes to: the type returned by the ``compress`` method of the subclass.
    808820    * Validates that the given value against each of the fields specified
    809821      as an argument to the ``MultiValueField``.
    810822    * Error message keys: ``required``, ``invalid``
    812     This abstract field (must be subclassed) aggregates the logic of multiple
    813     fields. Subclasses should not have to implement clean(). Instead, they must
    814     implement compress(), which takes a list of valid values and returns a
    815     "compressed" version of those values -- a single value.  For example,
    816     :class:`SplitDateTimeField` is a subclass which combines a time field and
    817     a date field into a datetime object.
    819 Takes one extra required argument:
    821824.. attribute:: MultiValueField.fields
    823     A list of fields which are cleaned into a single field. Each value in
    824     ``clean`` is cleaned by the corresponding field in ``fields`` -- the first
    825     value is cleaned by the first field, the second value is cleaned by
    826     the second field, etc.  Once all fields are cleaned, the list of clean
    827     values is "compressed" into a single value.
     826    A tuple of fields whose values are cleaned
     827    and
     828    subsequently combined into a single value.
     829    More specifically, each value of the field
     830    is cleaned by the corresponding field in ``fields``
     831    -- the first value is cleaned by the first field,
     832    the second value is cleaned by the second field, etc.
     833    Once all fields are cleaned,
     834    the list of clean values is combined into a single value
     835    by the :meth:`~forms.MultiValueField.compress`.
     837.. attribute:: MultiValueField.widget
     839    Must be a subclass of
     840    :class:`django.forms.MultiWidget`.
     841    Default value is :class:`~forms.widgets.TextInput`,
     842    which is probably is not very useful in this case.
     844.. method:: compress(data_list)
     846    takes a list of valid values and returns
     847    a "compressed" version of those values -- in a single value.
     848    For example, :class:`SplitDateTimeField` is a subclass which combines a time field and
     849    a date field into a datetime object.
     851    This method must be implemented in the subclasses.
  • docs/ref/forms/widgets.txt

    diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt
    index dbdf109..7b452b1 100644
    a b  
     5The term "widget" for the purposes of this document is narrower
     6than usually assumed elsewhere.
     8In Django, widget is a Python object responsible for three things:
     10#. generation of a subtree of HTML document
     11   where users can enter some data
     12#. extraction of raw data from the request's GET/POST dictionary
     13   entered into the element decribed above
     14#. optionally - provide media (e.g. javacript and CSS) for the widget
     16Objects of widget classes wrap "native HTML widget" elements:
     19``select`` and ``option``,
     20but in addition they may include other HTML constructs
     22may contain more than one "native HTML widget".
     24.. tip::
     26    Widgets should not be confused with the :doc:`form fields </ref/forms/fields>`.
     27    Form fields concern with the logic of input validation,
     28    and are directly used in the templates.
     29    Widgets purely deal with
     30    rendering of the data entry for display on the web page
     31    and
     32    extraction of raw submitted data.
     34    However, in order to take effect, widgets do need to be
     35    :ref:`assigned <widget-to-field>`
     36    to the form fields.
     38.. _builtin-widgets:
     40Built-in widgets
     43All built-in widgets are part of the ``django.forms.widgets`` module
     45handle many common use cases for
     46:ref:`the input of text <text-widgets>`,
     47:ref:`various checkboxes and selectors <selector-widgets>`,
     48:ref:`uploading files <file-upload-widgets>`,
     50:ref:`handling of multi-valued input <composite-widgets>`.
    552.. module:: django.forms.widgets
    653   :synopsis: Django's built-in form widgets.
    855.. currentmodule:: django.forms
    10 A widget is Django's representation of a HTML input element. The widget
    11 handles the rendering of the HTML, and the extraction of data from a GET/POST
    12 dictionary that corresponds to the widget.
     57.. _text-widgets:
     59Widgets handling input of text
    14 Django provides a representation of all the basic HTML widgets, plus some
    15 commonly used groups of widgets:
     62These widgets make use of the HTML elements `input` and `textarea`.
    1764.. class:: TextInput
    commonly used groups of widgets: 
    3077        form is re-displayed after a validation error (default is ``False``).
    3279.. versionchanged:: 1.3
    33     The default value for
    34     :attr:`~PasswordInput.render_value` was
     80    The default value for ``render_value`` was
    3581    changed from ``True`` to ``False``
    3783.. class:: HiddenInput
    3985    Hidden input: ``<input type='hidden' ...>``
    41 .. class:: MultipleHiddenInput
    43     Multiple ``<input type='hidden' ...>`` widgets.
    45 .. class:: FileInput
    47     File upload input: ``<input type='file' ...>``
    49 .. class:: ClearableFileInput
    51     .. versionadded:: 1.3
    53     File upload input: ``<input type='file' ...>``, with an additional checkbox
    54     input to clear the field's value, if the field is not required and has
    55     initial data.
     87    Please note that
     88    there also is a :ref:`MultipleHiddenInput <multiple-hidden>` widget
     89    that encapsulates a set of hidden input elements.
    5791.. class:: DateInput
    commonly used groups of widgets: 
    96130    Text area: ``<textarea>...</textarea>``
     132.. _selector-widgets:
     134Selector and checkbox widgets
    98137.. class:: CheckboxInput
    100139    Checkbox: ``<input type='checkbox' ...>``
    commonly used groups of widgets: 
    148187          ...
    149188        </ul>
    151 .. class:: MultiWidget
     190.. _file-upload-widgets:
     192File upload widgets
     195.. class:: FileInput
     197    File upload input: ``<input type='file' ...>``
     199.. class:: ClearableFileInput
     201    .. versionadded:: 1.3
    153     Wrapper around multiple other widgets
     203    File upload input: ``<input type='file' ...>``, with an additional checkbox
     204    input to clear the field's value, if the field is not required and has
     205    initial data.
     208.. _composite-widgets:
     210Composite widgets
    155213.. class:: SplitDateTimeWidget
    commonly used groups of widgets: 
    170228    Takes one optional argument:
    172     .. attribute:: List.years
     230    .. attribute:: SelectDateWidget.years
    174232        An optional list/tuple of years to use in the "year" select box.
    175233        The default is a list containing the current year and the next 9 years.
    commonly used groups of widgets: 
    181239        date = forms.DateField(widget=SelectDateWidget())
    183 Specifying widgets
    184 ------------------
    185 .. currentmodule:: django.forms
     241.. _multiple-hidden:
    187 .. attribute:: Form.widget
     243.. class:: MultipleHiddenInput
     245    Multiple ``<input type='hidden' ...>`` widgets.
     247.. _widget-to-field:
     249Assigning widgets to form fields
     251.. currentmodule:: django.forms
    189253Whenever you specify a field on a form, Django will use a default widget
    190254that is appropriate to the type of data that is to be displayed. To find
    191 which widget is used on which field, see the documentation for the
    192 built-in Field classes.
     255which widget is used on which field,
     256see the :ref:`documentation for the built-in Field classes
    194259However, if you want to use a different widget for a field, you can -
    195 just use the 'widget' argument on the field definition. For example::
     260just use the ``widget`` argument on the field definition. For example::
    197262    from django import forms
    just use the 'widget' argument on the field definition. For example:: 
    201266        url = forms.URLField()
    202267        comment = forms.CharField(widget=forms.Textarea)
    204 This would specify a form with a comment that uses a larger Textarea widget,
    205 rather than the default TextInput widget.
     269This will specify a form with a comment that uses a larger ``Textarea`` widget,
     270rather than the default ``TextInput`` widget.
     272Styling and adding behavior to widgets
     275When Django renders a widget as HTML,
     276it only produces the very minimal markup
     277- Django doesn't add class names
     279any other widget-specific attributes.
     280This means, for example, that
     281all instances of ``TextInput`` widget
     282will appear the same on your Web pages.
     284There are two ways to customize widgets:
     285:ref:`per widget instance <styling-widget-instances>`
     287:ref:`per widget class <styling-widget-classes>`.
    207 Customizing widget instances
    208 ----------------------------
     289.. _styling-widget-instances:
    210 When Django renders a widget as HTML, it only renders the bare minimum
    211 HTML - Django doesn't add a class definition, or any other widget-specific
    212 attributes. This means that all 'TextInput' widgets will appear the same
    213 on your Web page.
     291Styling widget instances
    215 If you want to make one widget look different to another, you need to
    216 specify additional attributes for each widget. When you specify a
    217 widget, you can provide a list of attributes that will be added to the
    218 rendered HTML for the widget.
     294If you want to make one widget instance look different from another,
     295all you will need to do is
     296specify additional attributes
     297- at the time when the widget object is instantiated
     298and assigned to a form field
     299(and perhaps add some rules to your .css files).
    220301For example, take the following simple form::
    each widget will be rendered exactly the same:: 
    234315    <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
    235316    <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
    238318On a real Web page, you probably don't want every widget to look the same. You
    239319might want a larger input element for the comment, and you might want the 'name'
    240320widget to have some special CSS class. To do this, you use the ``attrs``
    241 argument when creating the widget:
    243 .. attribute:: Widget.attrs
    245 For example::
     321argument when creating the widget::
    247323    class CommentForm(forms.Form):
    248324        name = forms.CharField(
    Django will then include the extra attributes in the rendered output:: 
    258334    <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
    259335    <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
    260336    <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
     338.. _styling-widget-classes:
     340Styling widget classes
     343With widgets, it is possible to add media (``css`` and ``javascript``)
     344and more deeply customise their appearance and behavior.
     346In a nutshell, you will need to subclass the widget
     347and either
     348:ref:`define a class "Media" <media-as-a-static-definition>`
     349as a member of the subclass,
     351:ref:`create a property "media" <dynamic-property>`,
     352returning an instance of that class.
     354These methods involve somewhat advanced Python programming and are
     355described in detail in the
     356:doc:`Form Media </topics/forms/media>` tutorial.
     358.. _base-widget-classes:
     360Base Widget classes
     363Base widget classes
     367are subclassed by
     368all the :ref:`built-in widgets <builtin-widgets>`
     369and may serve as a foundation for the custom ones
     370(but, please see the warning below).
     372.. warning::
     374   Interfaces of classes
     375   :class:`~django.forms.widgets.Widget`
     376   and
     377   :class:`~django.forms.widgets.MultiWidget`
     378   are still in flux,
     379   therefore -
     380   please take care to test all of your custom widgets
     381   when upgrading django.
     382   It is a particularly good idea to create
     383   :doc:`automated test suite </topics/testing>`
     384   for any of your custom widgets.
     386.. currentmodule:: django.forms
     388.. class:: Widget(attrs=None)
     390    .. method:: render(name, value, attrs=None)
     392       Returns HTML for the widget, as a Unicode string.
     393       This method must be implemented by the subclass,
     394       otherwise ``NotImplementedError`` will be raised.
     396       The 'value' given is not guaranteed to be valid input,
     397       therefore subclass implementations should program defensively.
     399.. class:: MultiWidget(widgets, attrs=None)
     401    A widget that is composed of multiple widgets.
     402    :class:`~django.forms.widgets.MultiWidget` works hand in hand
     403    with the :class:`~django.forms.MultiValueField`.
     405    .. method:: render(name, value, attrs=None)
     407        Argument `value` is handled differently in this method
     408        from the subclasses of :meth:`~django.forms.widgets.Widget`.
     410        If `value` is a list, output of
     411        :meth:`~django.forms.widgets.MultiWidget.render`
     412        will be a concatenation of rendered child widgets.
     413        If `value` is not a list, it will be first processed
     414        by the method :meth:`~django.forms.widgets.MultiWidget.decompress()`
     415        to create the list, and then processed as above.
     417        Unlike in the single value widgets,
     418        method :meth:`~django.forms.widgets.MultiWidget.render`
     419        should not be implemented in the subclasses
     420        of :class:`~django.forms.widgets.MultiWidget`.
     422    .. method:: decompress(value)
     424        Returns a list of "decompressed" values
     425        for the given value of the multi-value field
     426        that makes use of the widget.
     427        The input value can be assumed as valid,
     428        but not necessarily non-empty.
     430        This method **must be implemented** by the subclass,
     431        and since the value may be empty,
     432        the implementation must be defensive.
     434        The rationale behind "decompression" is that
     435        it is necessary to "split" the combined value
     436        of the form field into the values of the individual fields
     437        encapsulated within the multi-value field
     438        (e.g. when displaying the partially or fully filled-out form).
     440        .. tip::
     442            Please, note that :class:`~django.forms.MultiValueField` has
     443            a complementary method :meth:`~django.forms.MultiValueField.compress`
     444            with the opposite responsibility - combine cleaned values of
     445            all memeber fields into one.
     447.. custom-widgets:
     449Custom Widgets
     452Those who wish to create their own custom widgets
     453can use the APIs of classes
     458However, please do notice that those APIs
     459are subject to the future changes.
     461Since there are two :ref:`widget base classes <base-widget-classes>`,
     462two types of custom widgets are possible:
     463single-value widgets
     465multi-value composite widgets.
     466The patterns of their creation are somewhat different.
  • docs/topics/forms/media.txt

    diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt
    index 0eb3e91..2f6b3ec 100644
    a b in a form suitable for easy inclusion on your Web page. 
    3838    whichever toolkit suits your requirements. Django is able to integrate
    3939    with any JavaScript toolkit.
     41.. _media-as-a-static-definition:
    4143Media as a static definition
    declaration to the media declaration:: 
    164166    <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
    166168If you require even more control over media inheritance, define your media
    167 using a `dynamic property`_. Dynamic properties give you complete control over
     169using a :ref:`dynamic property <dynamic-property>` technique.
     170Dynamic properties give you complete control over
    168171which media files are inherited, and which are not.
    170 .. _dynamic property: `Media as a dynamic property`_
     173.. _dynamic-property:
    172175Media as a dynamic property
    Paths in media definitions 
    198201.. versionchanged:: 1.3
    200203Paths 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
     204starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an absolute
    202205path, and left as-is. All other paths will be prepended with the value of
    203206the appropriate prefix.
Back to Top