Browse Source

Refs #32339 -- Restructured outputting HTML form docs.

In the topic doc, promoted the Reusable form templates section.

In the reference, re-grouped and promoted the default __str__()
rendering path, and then gathered the various as_*() helpers
subsequently.

Thanks to David Smith for review.
Carlton Gibson 2 years ago
parent
commit
fde946daff
2 changed files with 149 additions and 118 deletions
  1. 78 50
      docs/ref/forms/api.txt
  2. 71 68
      docs/topics/forms/index.txt

+ 78 - 50
docs/ref/forms/api.txt

@@ -520,9 +520,15 @@ Although ``<table>`` output is the default output style when you ``print`` a
 form, other output styles are available. Each style is available as a method on
 form, other output styles are available. Each style is available as a method on
 a form object, and each rendering method returns a string.
 a form object, and each rendering method returns a string.
 
 
-``template_name``
+Default rendering
 -----------------
 -----------------
 
 
+The default rendering when you ``print`` a form uses the following methods and
+attributes.
+
+``template_name``
+~~~~~~~~~~~~~~~~~
+
 .. versionadded:: 4.0
 .. versionadded:: 4.0
 
 
 .. attribute:: Form.template_name
 .. attribute:: Form.template_name
@@ -540,8 +546,42 @@ class.
     In older versions ``template_name`` defaulted to the string value
     In older versions ``template_name`` defaulted to the string value
     ``'django/forms/default.html'``.
     ``'django/forms/default.html'``.
 
 
+``render()``
+~~~~~~~~~~~~
+
+.. versionadded:: 4.0
+
+.. method:: Form.render(template_name=None, context=None, renderer=None)
+
+The render method is called by ``__str__`` as well as the
+:meth:`.Form.as_table`, :meth:`.Form.as_p`, and :meth:`.Form.as_ul` methods.
+All arguments are optional and default to:
+
+* ``template_name``: :attr:`.Form.template_name`
+* ``context``: Value returned by :meth:`.Form.get_context`
+* ``renderer``: Value returned by :attr:`.Form.default_renderer`
+
+By passing ``template_name`` you can customize the template used for just a
+single call.
+
+``get_context()``
+~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 4.0
+
+.. method:: Form.get_context()
+
+Return the template context for rendering the form.
+
+The available context is:
+
+* ``form``: The bound form.
+* ``fields``: All bound fields, except the hidden fields.
+* ``hidden_fields``: All hidden bound fields.
+* ``errors``: All non field related or hidden field related form errors.
+
 ``template_name_label``
 ``template_name_label``
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 
 
 .. versionadded:: 4.0
 .. versionadded:: 4.0
 
 
@@ -552,15 +592,32 @@ The template used to render a field's ``<label>``, used when calling
 form by overriding this attribute or more generally by overriding the default
 form by overriding this attribute or more generally by overriding the default
 template, see also :ref:`overriding-built-in-form-templates`.
 template, see also :ref:`overriding-built-in-form-templates`.
 
 
+Output styles
+-------------
+
+As well as rendering the form directly, such as in a template with
+``{{ form }}``, the following helper functions serve as a proxy to
+:meth:`Form.render` passing a particular ``template_name`` value.
+
+These helpers are most useful in a template, where you need to override the
+form renderer or form provided value but cannot pass the additional parameter
+to :meth:`~Form.render`. For example, you can render a form as an unordered
+list using ``{{ form.as_ul }}``.
+
+Each helper pairs a form method with an attribute giving the appropriate
+template name.
+
 ``as_p()``
 ``as_p()``
-----------
+~~~~~~~~~~
+
+.. attribute:: Form.template_name_p
+
+The template used by ``as_p()``. Default: ``'django/forms/p.html'``.
 
 
 .. method:: Form.as_p()
 .. method:: Form.as_p()
 
 
-``as_p()`` renders the form using the template assigned to the forms
-``template_name_p`` attribute, by default this template is
-``'django/forms/p.html'``. This template renders the form as a series of
-``<p>`` tags, with each ``<p>`` containing one field::
+``as_p()`` renders the form as a series of ``<p>`` tags, with each ``<p>``
+containing one field::
 
 
     >>> f = ContactForm()
     >>> f = ContactForm()
     >>> f.as_p()
     >>> f.as_p()
@@ -572,16 +629,17 @@ template, see also :ref:`overriding-built-in-form-templates`.
     <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
     <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
 
 
 ``as_ul()``
 ``as_ul()``
------------
+~~~~~~~~~~~
+
+.. attribute:: Form.template_name_ul
+
+The template used by ``as_ul()``. Default: ``'django/forms/ul.html'``.
 
 
 .. method:: Form.as_ul()
 .. method:: Form.as_ul()
 
 
-``as_ul()`` renders the form using the template assigned to the forms
-``template_name_ul`` attribute, by default this template is
-``'django/forms/ul.html'``. This template renders the form as a series of
-``<li>`` tags, with each ``<li>`` containing one field. It does *not* include
-the ``<ul>`` or ``</ul>``, so that you can specify any HTML attributes on the
-``<ul>`` for flexibility::
+``as_ul()`` renders the form as a series of ``<li>`` tags, with each ``<li>``
+containing one field. It does *not* include the ``<ul>`` or ``</ul>``, so that
+you can specify any HTML attributes on the ``<ul>`` for flexibility::
 
 
     >>> f = ContactForm()
     >>> f = ContactForm()
     >>> f.as_ul()
     >>> f.as_ul()
@@ -593,14 +651,15 @@ the ``<ul>`` or ``</ul>``, so that you can specify any HTML attributes on the
     <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>
     <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>
 
 
 ``as_table()``
 ``as_table()``
---------------
+~~~~~~~~~~~~~~
+
+.. attribute:: Form.template_name_table
+
+The template used by ``as_table()``. Default: ``'django/forms/table.html'``.
 
 
 .. method:: Form.as_table()
 .. method:: Form.as_table()
 
 
-Finally, ``as_table()`` renders the form using the template assigned to the
-forms ``template_name_table`` attribute, by default this template is
-``'django/forms/table.html'``. This template outputs the form as an HTML
-``<table>``::
+``as_table()`` renders the form as an HTML ``<table>``::
 
 
     >>> f = ContactForm()
     >>> f = ContactForm()
     >>> f.as_table()
     >>> f.as_table()
@@ -611,37 +670,6 @@ forms ``template_name_table`` attribute, by default this template is
     <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
     <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
     <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
     <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
 
 
-``get_context()``
------------------
-
-.. versionadded:: 4.0
-
-.. method:: Form.get_context()
-
-Return context for form rendering in a template.
-
-The available context is:
-
-* ``form``: The bound form.
-* ``fields``: All bound fields, except the hidden fields.
-* ``hidden_fields``: All hidden bound fields.
-* ``errors``: All non field related or hidden field related form errors.
-
-``render()``
-------------
-
-.. versionadded:: 4.0
-
-.. method:: Form.render(template_name=None, context=None, renderer=None)
-
-The render method is called by ``__str__`` as well as the
-:meth:`.Form.as_table`, :meth:`.Form.as_p`, and :meth:`.Form.as_ul` methods.
-All arguments are optional and default to:
-
-* ``template_name``: :attr:`.Form.template_name`
-* ``context``: Value returned by :meth:`.Form.get_context`
-* ``renderer``: Value returned by :attr:`.Form.default_renderer`
-
 .. _ref-forms-api-styling-form-rows:
 .. _ref-forms-api-styling-form-rows:
 
 
 Styling required or erroneous form rows
 Styling required or erroneous form rows

+ 71 - 68
docs/topics/forms/index.txt

@@ -487,15 +487,83 @@ instance into the template context. So if your form is called ``form`` in the
 context, ``{{ form }}`` will render its ``<label>`` and ``<input>`` elements
 context, ``{{ form }}`` will render its ``<label>`` and ``<input>`` elements
 appropriately.
 appropriately.
 
 
-Form rendering options
-----------------------
-
 .. admonition:: Additional form template furniture
 .. admonition:: Additional form template furniture
 
 
     Don't forget that a form's output does *not* include the surrounding
     Don't forget that a form's output does *not* include the surrounding
     ``<form>`` tags, or the form's ``submit`` control. You will have to provide
     ``<form>`` tags, or the form's ``submit`` control. You will have to provide
     these yourself.
     these yourself.
 
 
+Reusable form templates
+-----------------------
+
+The HTML output when rendering a form is itself generated via a template. You
+can control this by creating an appropriate template file and setting a custom
+:setting:`FORM_RENDERER` to use that
+:attr:`~django.forms.renderers.BaseRenderer.form_template_name` site-wide. You
+can also customize per-form by overriding the form's
+:attr:`~django.forms.Form.template_name` attribute to render the form using the
+custom template, or by passing the template name directly to
+:meth:`.Form.render`.
+
+The example below will result in ``{{ form }}`` being rendered as the output of
+the ``form_snippet.html`` template.
+
+In your templates:
+
+.. code-block:: html+django
+
+    # In your template:
+    {{ form }}
+
+    # In form_snippet.html:
+    {% for field in form %}
+        <div class="fieldWrapper">
+            {{ field.errors }}
+            {{ field.label_tag }} {{ field }}
+        </div>
+    {% endfor %}
+
+Then you can configure the :setting:`FORM_RENDERER` setting:
+
+.. code-block:: python
+    :caption: settings.py
+
+    from django.forms.renderers import TemplatesSetting
+
+    class CustomFormRenderer(TemplatesSetting):
+        form_template_name = "form_snippet.html"
+
+    FORM_RENDERER = "project.settings.CustomFormRenderer"
+
+… or for a single form::
+
+    class MyForm(forms.Form):
+        template_name = "form_snippet.html"
+        ...
+
+… or for a single render of a form instance, passing in the template name to
+the :meth:`.Form.render`. Here's an example of this being used in a view::
+
+    def index(request):
+        form = MyForm()
+        rendered_form = form.render("form_snippet.html")
+        context = {'form': rendered_form}
+        return render(request, 'index.html', context)
+
+See :ref:`ref-forms-api-outputting-html` for more details.
+
+.. versionchanged:: 4.0
+
+    Template rendering of forms was added.
+
+.. versionchanged:: 4.1
+
+    The ability to set the default ``form_template_name`` on the form renderer
+    was added.
+
+Form rendering options
+----------------------
+
 There are other output options though for the ``<label>``/``<input>`` pairs:
 There are other output options though for the ``<label>``/``<input>`` pairs:
 
 
 * ``{{ form.as_table }}`` will render them as table cells wrapped in ``<tr>``
 * ``{{ form.as_table }}`` will render them as table cells wrapped in ``<tr>``
@@ -754,71 +822,6 @@ error in a hidden field is a sign of form tampering, since normal form
 interaction won't alter them. However, you could easily insert some error
 interaction won't alter them. However, you could easily insert some error
 displays for those form errors, as well.
 displays for those form errors, as well.
 
 
-Reusable form templates
------------------------
-
-If your site uses the same rendering logic for forms in multiple places, you
-can reduce duplication by saving the form's loop in a standalone template and
-setting a custom :setting:`FORM_RENDERER` to use that
-:attr:`~django.forms.renderers.BaseRenderer.form_template_name` site-wide. You
-can also customize per-form by overriding the form's
-:attr:`~django.forms.Form.template_name` attribute to render the form using the
-custom template.
-
-The below example will result in ``{{ form }}`` being rendered as the output of
-the ``form_snippet.html`` template.
-
-In your templates:
-
-.. code-block:: html+django
-
-    # In your template:
-    {{ form }}
-
-    # In form_snippet.html:
-    {% for field in form %}
-        <div class="fieldWrapper">
-            {{ field.errors }}
-            {{ field.label_tag }} {{ field }}
-        </div>
-    {% endfor %}
-
-Then you can configure the :setting:`FORM_RENDERER` setting:
-
-.. code-block:: python
-    :caption: settings.py
-
-    from django.forms.renderers import TemplatesSetting
-
-    class CustomFormRenderer(TemplatesSetting):
-        form_template_name = "form_snippet.html"
-
-    FORM_RENDERER = "project.settings.CustomFormRenderer"
-
-… or for a single form::
-
-    class MyForm(forms.Form):
-        template_name = "form_snippet.html"
-        ...
-
-… or for a single render of a form instance, passing in the template name to
-the :meth:`.Form.render()`. Here's an example of this being used in a view::
-
-    def index(request):
-        form = MyForm()
-        rendered_form = form.render("form_snippet.html")
-        context = {'form': rendered_form}
-        return render(request, 'index.html', context)
-
-.. versionchanged:: 4.0
-
-    Template rendering of forms was added.
-
-.. versionchanged:: 4.1
-
-    The ability to set the default ``form_template_name`` on the form renderer
-    was added.
-
 Further topics
 Further topics
 ==============
 ==============