diff options
author | David Smith <smithdc@gmail.com> | 2022-11-02 20:13:16 +0000 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-03-24 10:16:30 +0100 |
commit | cad376f844c7bdeeee7607a7c0ea8ae52061309b (patch) | |
tree | 674bcfb8a4b99c752bff23c029494987ed62f5ef /docs | |
parent | d33368b4ab6ae0c01e83d525f7e1655156a640d1 (diff) | |
download | django-cad376f844c7bdeeee7607a7c0ea8ae52061309b.tar.gz |
Fixed #34077 -- Added form field rendering.
Diffstat (limited to 'docs')
-rw-r--r-- | docs/ref/forms/api.txt | 40 | ||||
-rw-r--r-- | docs/ref/forms/fields.txt | 13 | ||||
-rw-r--r-- | docs/ref/forms/renderers.txt | 31 | ||||
-rw-r--r-- | docs/releases/5.0.txt | 63 | ||||
-rw-r--r-- | docs/topics/forms/index.txt | 68 |
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 |