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
 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
 
 .. attribute:: Form.template_name
@@ -540,8 +546,42 @@ class.
     In older versions ``template_name`` defaulted to the string value
     ``'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``
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 
 .. 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
 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()``
-----------
+~~~~~~~~~~
+
+.. attribute:: Form.template_name_p
+
+The template used by ``as_p()``. Default: ``'django/forms/p.html'``.
 
 .. 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.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>
 
 ``as_ul()``
------------
+~~~~~~~~~~~
+
+.. attribute:: Form.template_name_ul
+
+The template used by ``as_ul()``. Default: ``'django/forms/ul.html'``.
 
 .. 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.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>
 
 ``as_table()``
---------------
+~~~~~~~~~~~~~~
+
+.. attribute:: Form.template_name_table
+
+The template used by ``as_table()``. Default: ``'django/forms/table.html'``.
 
 .. 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.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_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:
 
 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
 appropriately.
 
-Form rendering options
-----------------------
-
 .. admonition:: Additional form template furniture
 
     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
     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:
 
 * ``{{ 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
 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
 ==============