Commit 535809e1 authored by Moritz Sichert's avatar Moritz Sichert Committed by Tim Graham
Browse files

Fixed #25294 -- Allowed custom BoundFields on forms.

parent 8615e415
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -204,6 +204,14 @@ class Field(six.with_metaclass(RenameFieldMethods, object)):
        data_value = data if data is not None else ''
        return initial_value != data_value

    def get_bound_field(self, form, field_name):
        """
        Return a BoundField instance that will be used when accessing the form
        field in a template.
        """
        from django.forms.forms import BoundField
        return BoundField(form, self, field_name)

    def __deepcopy__(self, memo):
        result = copy.copy(self)
        memo[id(self)] = result
+1 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ class BaseForm(object):
            raise KeyError(
                "Key %r not found in '%s'" % (name, self.__class__.__name__))
        if name not in self._bound_fields_cache:
            self._bound_fields_cache[name] = BoundField(self, field, name)
            self._bound_fields_cache[name] = field.get_bound_field(self, name)
        return self._bound_fields_cache[name]

    @property
+42 −0
Original line number Diff line number Diff line
@@ -932,6 +932,48 @@ and using the template above, would render something like:

    <label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" />

Customizing ``BoundField``
--------------------------

.. versionadded:: 1.9

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`.

A custom form field can override ``get_bound_field()``:

.. method:: Field.get_bound_field(form, field_name)

    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 you have a ``GPSCoordinatesField``, for example, and want to be able to
access additional information about the coordinates in a template, this could
be implemented as follows::

    class GPSCoordinatesBoundField(BoundField):
        @property
        def country(self):
            """
            Return the country the coordinates lie in or None if it can't be
            determined.
            """
            value = self.value()
            if value:
                return get_country_from_coordinates(value)
            else:
                return None

    class GPSCoordinatesField(Field):
        def get_bound_field(self, form, field_name):
            return GPSCoordinatesBoundField(form, self, field_name)

Now you can access the country in a template with
``{{ form.coordinates.country }}``.

.. _binding-uploaded-files:

Binding uploaded files to a form
+3 −0
Original line number Diff line number Diff line
@@ -1239,3 +1239,6 @@ custom ``Field`` classes. To do this, just create a subclass of
``clean()`` method and that its ``__init__()`` method accept the core arguments
mentioned above (``required``, ``label``, ``initial``, ``widget``,
``help_text``).

You can also customize how a field will be accessed by overriding
:meth:`~django.forms.Field.get_bound_field()`.
+3 −0
Original line number Diff line number Diff line
@@ -364,6 +364,9 @@ Forms
* Form fields now support the :attr:`~django.forms.Field.disabled` argument,
  allowing the field widget to be displayed disabled by browsers.

* It's now possible to customize bound fields by overriding a field's
  :meth:`~django.forms.Field.get_bound_field()` method.

Generic Views
^^^^^^^^^^^^^

Loading