v0.156.1
 1from __future__ import annotations
 2
 3from functools import cached_property
 4from typing import TYPE_CHECKING, Any
 5
 6if TYPE_CHECKING:
 7    from .fields import Field
 8    from .forms import BaseForm
 9
10__all__ = ["BoundField"]
11
12
13class BoundField:
14    "A Field plus data"
15
16    def __init__(self, form: BaseForm, field: Field, name: str):
17        self._form = form
18        self.field = field
19        self.name = name
20        self.html_name = form.add_prefix(name)
21        self.html_id = form.add_prefix(self._auto_id)
22
23    def __repr__(self) -> str:
24        return f'<{self.__class__.__name__} "{self.html_name}">'
25
26    @property
27    def errors(self) -> list[str]:
28        """
29        Return an error list (empty if there are no errors) for this field.
30        """
31        return self._form.errors.get(self.name, [])
32
33    def value(self) -> Any:
34        """
35        Return the value for this BoundField, using the initial value if
36        the form is not bound or the data otherwise.
37        """
38        data = self.initial
39        if self._form.is_bound:
40            data = self.field.bound_data(
41                self._form._field_data_value(self.field, self.html_name), data
42            )
43        return self.field.prepare_value(data)
44
45    @cached_property
46    def initial(self) -> Any:
47        return self._form.get_initial_for_field(self.field, self.name)
48
49    def _has_changed(self) -> bool:
50        return self.field.has_changed(
51            self.initial, self._form._field_data_value(self.field, self.html_name)
52        )
53
54    @property
55    def _auto_id(self) -> str:
56        """
57        Calculate and return the ID attribute for this BoundField, if the
58        associated Form has specified auto_id. Return an empty string otherwise.
59        """
60        auto_id = self._form._auto_id  # Boolean or string
61        if auto_id and isinstance(auto_id, str) and "%s" in auto_id:
62            return auto_id % self.html_name
63        elif auto_id:
64            return self.html_name
65        return ""