summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorDavid Smith <smithdc@gmail.com>2022-11-02 20:13:16 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-03-24 10:16:30 +0100
commitcad376f844c7bdeeee7607a7c0ea8ae52061309b (patch)
tree674bcfb8a4b99c752bff23c029494987ed62f5ef /docs
parentd33368b4ab6ae0c01e83d525f7e1655156a640d1 (diff)
downloaddjango-cad376f844c7bdeeee7607a7c0ea8ae52061309b.tar.gz
Fixed #34077 -- Added form field rendering.
Diffstat (limited to 'docs')
-rw-r--r--docs/ref/forms/api.txt40
-rw-r--r--docs/ref/forms/fields.txt13
-rw-r--r--docs/ref/forms/renderers.txt31
-rw-r--r--docs/releases/5.0.txt63
-rw-r--r--docs/topics/forms/index.txt68
5 files changed, 211 insertions, 4 deletions
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 12754dbae5..4d4f73d0b4 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -1257,6 +1257,16 @@ Attributes of ``BoundField``
>>> print(f["message"].name)
message
+.. attribute:: BoundField.template_name
+
+ .. versionadded:: 5.0
+
+ The name of the template rendered with :meth:`.BoundField.as_field_group`.
+
+ A property returning the value of the
+ :attr:`~django.forms.Field.template_name` if set otherwise
+ :attr:`~django.forms.renderers.BaseRenderer.field_template_name`.
+
.. attribute:: BoundField.use_fieldset
Returns the value of this BoundField widget's ``use_fieldset`` attribute.
@@ -1281,6 +1291,15 @@ Attributes of ``BoundField``
Methods of ``BoundField``
-------------------------
+.. method:: BoundField.as_field_group()
+
+ .. versionadded:: 5.0
+
+ Renders the field using :meth:`.BoundField.render` with default values
+ which renders the ``BoundField``, including its label, help text and errors
+ using the template's :attr:`~django.forms.Field.template_name` if set
+ otherwise :attr:`~django.forms.renderers.BaseRenderer.field_template_name`
+
.. method:: BoundField.as_hidden(attrs=None, **kwargs)
Returns a string of HTML for representing this as an ``<input type="hidden">``.
@@ -1321,6 +1340,13 @@ Methods of ``BoundField``
>>> f["message"].css_classes("foo bar")
'foo bar required'
+.. method:: BoundField.get_context()
+
+ .. versionadded:: 5.0
+
+ Return the template context for rendering the field. The available context
+ is ``field`` being the instance of the bound field.
+
.. method:: BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None)
Renders a label tag for the form field using the template specified by
@@ -1368,6 +1394,20 @@ Methods of ``BoundField``
checkbox widgets where ``<legend>`` may be more appropriate than a
``<label>``.
+.. method:: BoundField.render(template_name=None, context=None, renderer=None)
+
+ .. versionadded:: 5.0
+
+ The render method is called by ``as_field_group``. All arguments are
+ optional and default to:
+
+ * ``template_name``: :attr:`.BoundField.template_name`
+ * ``context``: Value returned by :meth:`.BoundField.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.
+
.. method:: BoundField.value()
Use this method to render the raw value of this field as it would be rendered
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index 7d975a74d5..476075b936 100644
--- a/docs/ref/forms/fields.txt
+++ b/docs/ref/forms/fields.txt
@@ -337,6 +337,19 @@ using the ``disabled`` HTML attribute so that it won't be editable by users.
Even if a user tampers with the field's value submitted to the server, it will
be ignored in favor of the value from the form's initial data.
+``template_name``
+-----------------
+
+.. attribute:: Field.template_name
+
+.. versionadded:: 5.0
+
+The ``template_name`` argument allows a custom template to be used when the
+field is rendered with :meth:`~django.forms.BoundField.as_field_group`. By
+default this value is set to ``"django/forms/field.html"``. Can be changed per
+field by overriding this attribute or more generally by overriding the default
+template, see also :ref:`overriding-built-in-field-templates`.
+
Checking if the field data has changed
======================================
diff --git a/docs/ref/forms/renderers.txt b/docs/ref/forms/renderers.txt
index 6b4eb95cd7..053b5998c1 100644
--- a/docs/ref/forms/renderers.txt
+++ b/docs/ref/forms/renderers.txt
@@ -59,6 +59,14 @@ should return a rendered templates (as a string) or raise
Defaults to ``"django/forms/formsets/div.html"`` template.
+ .. attribute:: field_template_name
+
+ .. versionadded:: 5.0
+
+ The default name of the template used to render a ``BoundField``.
+
+ Defaults to ``"django/forms/field.html"``
+
.. method:: get_template(template_name)
Subclasses must implement this method with the appropriate template
@@ -162,6 +170,16 @@ forms receive a dictionary with the following values:
* ``hidden_fields``: All hidden bound fields.
* ``errors``: All non field related or hidden field related form errors.
+Context available in field templates
+====================================
+
+.. versionadded:: 5.0
+
+Field templates receive a context from :meth:`.BoundField.get_context`. By
+default, fields receive a dictionary with the following values:
+
+* ``field``: The :class:`~django.forms.BoundField`.
+
Context available in widget templates
=====================================
@@ -201,6 +219,19 @@ To override form templates, you must use the :class:`TemplatesSetting`
renderer. Then overriding widget templates works :doc:`the same as
</howto/overriding-templates>` overriding any other template in your project.
+.. _overriding-built-in-field-templates:
+
+Overriding built-in field templates
+===================================
+
+.. versionadded:: 5.0
+
+:attr:`.Field.template_name`
+
+To override field templates, you must use the :class:`TemplatesSetting`
+renderer. Then overriding field templates works :doc:`the same as
+</howto/overriding-templates>` overriding any other template in your project.
+
.. _overriding-built-in-widget-templates:
Overriding built-in widget templates
diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt
index b2e8b9d48b..08de2a3740 100644
--- a/docs/releases/5.0.txt
+++ b/docs/releases/5.0.txt
@@ -45,6 +45,69 @@ toggled on via the UI. This behavior can be changed via the new
:attr:`.ModelAdmin.show_facets` attribute. For more information see
:ref:`facet-filters`.
+Simplified templates for form field rendering
+---------------------------------------------
+
+Django 5.0 introduces the concept of a field group, and field group templates.
+This simplifies rendering of the related elements of a Django form field such
+as its label, widget, help text, and errors.
+
+For example, the template below:
+
+.. code-block:: html+django
+
+ <form>
+ ...
+ <div>
+ {{ form.name.label }}
+ {% if form.name.help_text %}
+ <div class="helptext">{{ form.name.help_text|safe }}</div>
+ {% endif %}
+ {{ form.name.errors }}
+ {{ form.name }}
+ <div class="row">
+ <div class="col">
+ {{ form.email.label }}
+ {% if form.email.help_text %}
+ <div class="helptext">{{ form.email.help_text|safe }}</div>
+ {% endif %}
+ {{ form.email.errors }}
+ {{ form.email }}
+ </div>
+ <div class="col">
+ {{ form.password.label }}
+ {% if form.password.help_text %}
+ <div class="helptext">{{ form.password.help_text|safe }}</div>
+ {% endif %}
+ {{ form.password.errors }}
+ {{ form.password }}
+ </div>
+ </div>
+ </div>
+ ...
+ </form>
+
+Can now be simplified to:
+
+.. code-block:: html+django
+
+ <form>
+ ...
+ <div>
+ {{ form.name.as_field_group }}
+ <div class="row">
+ <div class="col">{{ form.email.as_field_group }}</div>
+ <div class="col">{{ form.password.as_field_group }}</div>
+ </div>
+ </div>
+ ...
+ </form>
+
+:meth:`~django.forms.BoundField.as_field_group` renders fields with the
+``"django/forms/field.html"`` template by default and can be customized on a
+per-project, per-field, or per-request basis. See
+:ref:`reusable-field-group-templates`.
+
Minor features
--------------
diff --git a/docs/topics/forms/index.txt b/docs/topics/forms/index.txt
index fec2b03251..27ea496ca6 100644
--- a/docs/topics/forms/index.txt
+++ b/docs/topics/forms/index.txt
@@ -559,13 +559,73 @@ the :meth:`.Form.render`. Here's an example of this being used in a view::
See :ref:`ref-forms-api-outputting-html` for more details.
+.. _reusable-field-group-templates:
+
+Reusable field group templates
+------------------------------
+
+.. versionadded:: 5.0
+
+Each field is available as an attribute of the form, using
+``{{form.name_of_field }}`` in a template. A field has a
+:meth:`~django.forms.BoundField.as_field_group` method which renders the
+related elements of the field as a group, its label, widget, errors, and help
+text.
+
+This allows generic templates to be written that arrange fields elements in the
+required layout. For example:
+
+.. code-block:: html+django
+
+ {{ form.non_field_errors }}
+ <div class="fieldWrapper">
+ {{ form.subject.as_field_group }}
+ </div>
+ <div class="fieldWrapper">
+ {{ form.message.as_field_group }}
+ </div>
+ <div class="fieldWrapper">
+ {{ form.sender.as_field_group }}
+ </div>
+ <div class="fieldWrapper">
+ {{ form.cc_myself.as_field_group }}
+ </div>
+
+By default Django uses the ``"django/forms/field.html"`` template which is
+designed for use with the default ``"django/forms/div.html"`` form style.
+
+The default template can be customized by by setting
+:attr:`~django.forms.renderers.BaseRenderer.field_template_name` in your
+project-level :setting:`FORM_RENDERER`::
+
+ from django.forms.renderers import TemplatesSetting
+
+
+ class CustomFormRenderer(TemplatesSetting):
+ field_template_name = "field_snippet.html"
+
+… or on a single field::
+
+ class MyForm(forms.Form):
+ subject = forms.CharField(template_name="my_custom_template.html")
+ ...
+
+… or on a per-request basis by calling
+:meth:`.BoundField.render` and supplying a template name::
+
+ def index(request):
+ form = ContactForm()
+ subject = form["subject"]
+ context = {"subject": subject.render("my_custom_template.html")}
+ return render(request, "index.html", context)
+
Rendering fields manually
-------------------------
-We don't have to let Django unpack the form's fields; we can do it manually if
-we like (allowing us to reorder the fields, for example). Each field is
-available as an attribute of the form using ``{{ form.name_of_field }}``, and
-in a Django template, will be rendered appropriately. For example:
+More fine grained control over field rendering is also possible. Likely this
+will be in a custom field template, to allow the template to be written once
+and reused for each field. However, it can also be directly accessed from the
+field attribute on the form. For example:
.. code-block:: html+django