summaryrefslogtreecommitdiff
path: root/docs/ref/forms
diff options
context:
space:
mode:
Diffstat (limited to 'docs/ref/forms')
-rw-r--r--docs/ref/forms/api.txt106
-rw-r--r--docs/ref/forms/fields.txt22
-rw-r--r--docs/ref/forms/renderers.txt12
3 files changed, 127 insertions, 13 deletions
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 1b1ecbec6c..9b827ca69a 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -822,6 +822,9 @@ classes, as needed. The HTML will look something like:
>>> f["subject"].legend_tag(attrs={"class": "foo"})
<legend for="id_subject" class="foo required">Subject:</legend>
+You may further modify the rendering of form rows by using a
+:ref:`custom BoundField <custom-boundfield>`.
+
.. _ref-forms-api-configuring-label:
Configuring form elements' HTML ``id`` attributes and ``<label>`` tags
@@ -1149,6 +1152,12 @@ they're not the only way a form object can be displayed.
The ``__str__()`` method of this object displays the HTML for this field.
+ You can use :attr:`.Form.bound_field_class` and
+ :attr:`.Field.bound_field_class` to specify a different ``BoundField`` class
+ per form or per field, respectively.
+
+ See :ref:`custom-boundfield` for examples of overriding a ``BoundField``.
+
To retrieve a single ``BoundField``, use dictionary lookup syntax on your form
using the field's name as the key:
@@ -1488,23 +1497,34 @@ Methods of ``BoundField``
>>> print(bound_form["subject"].value())
hi
+.. _custom-boundfield:
+
Customizing ``BoundField``
==========================
-If you need to access some additional information about a form field in a
-template and using a subclass of :class:`~django.forms.Field` isn't
-sufficient, consider also customizing :class:`~django.forms.BoundField`.
+.. attribute:: Form.bound_field_class
-A custom form field can override ``get_bound_field()``:
+.. versionadded:: 5.2
-.. method:: Field.get_bound_field(form, field_name)
+Define a custom :class:`~django.forms.BoundField` class to use when rendering
+the form. This takes precedence over the project-level
+:attr:`.BaseRenderer.bound_field_class` (along with a custom
+:setting:`FORM_RENDERER`), but can be overridden by the field-level
+:attr:`.Field.bound_field_class`.
- Takes an instance of :class:`~django.forms.Form` and the name of the field.
- The return value will be used when accessing the field in a template. Most
- likely it will be an instance of a subclass of
- :class:`~django.forms.BoundField`.
+If not defined as a class variable, ``bound_field_class`` can be set via the
+``bound_field_class`` argument in the :class:`Form` or :class:`Field`
+constructor.
-If you have a ``GPSCoordinatesField``, for example, and want to be able to
+For compatibility reasons, a custom form field can still override
+:meth:`.Field.get_bound_field()` to use a custom class, though any of the
+previous options are preferred.
+
+You may want to use a custom :class:`.BoundField` if you need to access some
+additional information about a form field in a template and using a subclass of
+:class:`~django.forms.Field` isn't sufficient.
+
+For example, if you have a ``GPSCoordinatesField``, and want to be able to
access additional information about the coordinates in a template, this could
be implemented as follows::
@@ -1523,12 +1543,74 @@ be implemented as follows::
class GPSCoordinatesField(Field):
- def get_bound_field(self, form, field_name):
- return GPSCoordinatesBoundField(form, self, field_name)
+ bound_field_class = GPSCoordinatesBoundField
Now you can access the country in a template with
``{{ form.coordinates.country }}``.
+You may also want to customize the default form field template rendering. For
+example, you can override :meth:`.BoundField.label_tag` to add a custom class::
+
+ class StyledLabelBoundField(BoundField):
+ def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None):
+ attrs = attrs or {}
+ attrs["class"] = "wide"
+ return super().label_tag(contents, attrs, label_suffix, tag)
+
+
+ class UserForm(forms.Form):
+ bound_field_class = StyledLabelBoundField
+ name = CharField()
+
+This would update the default form rendering:
+
+.. code-block:: pycon
+
+ >>> f = UserForm()
+ >>> print(f["name"].label_tag)
+ <label for="id_name" class="wide">Name:</label>
+
+To add a CSS class to the wrapping HTML element of all fields, a ``BoundField``
+can be overridden to return a different collection of CSS classes::
+
+ class WrappedBoundField(BoundField):
+ def css_classes(self, extra_classes=None):
+ parent_css_classes = super().css_classes(extra_classes)
+ return f"field-class {parent_css_classes}".strip()
+
+
+ class UserForm(forms.Form):
+ bound_field_class = WrappedBoundField
+ name = CharField()
+
+This would update the form rendering as follows:
+
+.. code-block:: pycon
+
+ >>> f = UserForm()
+ >>> print(f)
+ <div class="field-class"><label for="id_name">Name:</label><input type="text" name="name" required id="id_name"></div>
+
+Alternatively, to override the ``BoundField`` class at the project level,
+:attr:`.BaseRenderer.bound_field_class` can be defined on a custom
+:setting:`FORM_RENDERER`:
+
+.. code-block:: python
+ :caption: ``mysite/renderers.py``
+
+ from django.forms.renderers import DjangoTemplates
+
+ from .forms import CustomBoundField
+
+
+ class CustomRenderer(DjangoTemplates):
+ bound_field_class = CustomBoundField
+
+.. code-block:: python
+ :caption: ``settings.py``
+
+ FORM_RENDERER = "mysite.renderers.CustomRenderer"
+
.. _binding-uploaded-files:
Binding uploaded files to a form
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index c0ab4f2434..7ae5c121eb 100644
--- a/docs/ref/forms/fields.txt
+++ b/docs/ref/forms/fields.txt
@@ -397,6 +397,16 @@ 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`.
+``bound_field_class``
+---------------------
+
+.. attribute:: Field.bound_field_class
+
+.. versionadded:: 5.2
+
+The ``bound_field_class`` attribute allows a per-field override of
+:attr:`.Form.bound_field_class`.
+
Checking if the field data has changed
======================================
@@ -1635,4 +1645,14 @@ only requirements are that it implement a ``clean()`` method and that its
``label``, ``initial``, ``widget``, ``help_text``).
You can also customize how a field will be accessed by overriding
-:meth:`~django.forms.Field.get_bound_field()`.
+:attr:`~django.forms.Field.bound_field_class` or override
+:meth:`.Field.get_bound_field()` if you need more flexibility when creating
+the ``BoundField``:
+
+.. method:: Field.get_bound_field(form, field_name)
+
+ Takes an instance of :class:`~django.forms.Form` and the name of the field.
+ The returned :class:`.BoundField` instance will be used when accessing the
+ field in a template.
+
+See :ref:`custom-boundfield` for examples of overriding a ``BoundField``.
diff --git a/docs/ref/forms/renderers.txt b/docs/ref/forms/renderers.txt
index e527a70c57..f52534651a 100644
--- a/docs/ref/forms/renderers.txt
+++ b/docs/ref/forms/renderers.txt
@@ -65,6 +65,18 @@ should return a rendered templates (as a string) or raise
Defaults to ``"django/forms/field.html"``
+ .. attribute:: bound_field_class
+
+ .. versionadded:: 5.2
+
+ The default class used to represent form fields across the project.
+
+ Defaults to :class:`.BoundField` class.
+
+ This can be customized further using :attr:`.Form.bound_field_class`
+ for per-form overrides, or :attr:`.Field.bound_field_class` for
+ per-field overrides.
+
.. method:: get_template(template_name)
Subclasses must implement this method with the appropriate template