# Django 5.2.8 documentation

# 表单 API

关于此文档

本文档介绍了 Django 的表单 API 的具体细节。你应该先阅读 使用表单的介绍。

## 绑定和非绑定表单

一个 `Form` 实例要么是 绑定 到一组数据，要么是 未绑定。

- 如果是 绑定 了一组数据，它就能够验证这些数据，并将表单渲染成 HTML，并在 HTML 中显示数据。

- 如果是 未绑定，它就不能进行验证（因为没有数据可验证！），但它仍然可以将空白表单渲染为 HTML。

class Form

要创建一个未绑定的 `Form` 实例，实例化这个类：

    >>> f = ContactForm()

要将数据绑定到表单，将数据作为字典传递给 `Form` 类构造函数的第一个参数：

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data)

在这个字典中，键是字段名，对应于 `Form` 类中的属性。值是你要验证的数据。这些数据通常是字符串，但不要求它们是字符串；你传递的数据类型取决于 `Field`，我们稍后会看到。

Form.is_bound

如果在运行时需要区分绑定和未绑定的表单实例，请检查表单的 `is_bound` 属性的值：

    >>> f = ContactForm()
    >>> f.is_bound
    False
    >>> f = ContactForm({"subject": "hello"})
    >>> f.is_bound
    True

请注意，传递一个空字典会创建一个带有空数据的 绑定 表单：

    >>> f = ContactForm({})
    >>> f.is_bound
    True

如果你有一个绑定的 `Form` 实例，并想以某种方式改变数据，或者你想将一个未绑定的 `Form` 实例绑定到一些数据，请创建另一个 `Form` 实例。没有办法改变一个 `Form` 实例中的数据。一旦创建了一个 `Form` 实例，你应该认为它的数据是不可改变的，不管它是否有数据。

## 使用表单来验证数据

Form.clean()

当你必须为相互依赖的字段添加自定义验证时，在你的 `Form` 上实现一个 `clean()` 方法。参见 清理和验证相互依赖的字段 的用法示例。

Form.is_valid()

`Form` 对象的主要任务是验证数据。对于一个绑定的 `Form` 实例，调用 `is_valid()` 方法来运行验证，并返回一个布尔值，表示数据是否有效：

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    True

让我们尝试一些无效的数据。在这种情况下，`subject` 是空白的（这是一个错误，因为默认情况下所有字段都是必填的），而 `sender` 不是一个有效的电子邮件地址：

    >>> data = {
    ...     "subject": "",
    ...     "message": "Hi there",
    ...     "sender": "invalid email address",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    False

Form.errors

访问 `errors` 属性以获取错误消息的字典：

    >>> f.errors
    {'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}

在这个字典中，键是字段名，值是代表错误信息的字符串列表。错误信息存储在列表中，因为一个字段可以有多个错误信息。

你可以访问 `errors`，而不必先调用 `is_valid()`。无论是调用 `is_valid()` 还是访问 `errors`，表单的数据都会首先被验证。

验证例程只会被调用一次，无论你访问 `errors` 或调用 `is_valid()` 多少次。这意味着，如果验证有副作用，这些副作用将只被触发一次。

Form.errors.as_data()

返回一个 `dict`，将字段映射到它们的原始 `ValidationError` 实例。

    >>> f.errors.as_data()
    {'sender': [ValidationError(['Enter a valid email address.'])],
    'subject': [ValidationError(['This field is required.'])]}

Use this method anytime you need to identify an error by its `code`. This enables things like rewriting the error's message or writing custom logic in a view when a given error is present. It can also be used to serialize the errors in a custom format (e.g. XML); for instance, `as_json()` relies on `as_data()`.

需要使用 `as_data()` 方法是由于向后兼容性。以前，`ValidationError` 实例一旦被添加到 `Form.errors` 字典中，其 渲染的 错误信息就会丢失。理想情况下，`Form.errors` 会存储 `ValidationError` 实例，并且带有 `as_` 前缀的方法可以渲染它们，但为了不破坏那些期望在 `Form.errors` 中渲染错误信息的代码，必须反过来做。

Form.errors.as_json(escape_html=False)

返回以 JSON 格式序列化的错误。

    >>> f.errors.as_json()
    {"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
    "subject": [{"message": "This field is required.", "code": "required"}]}

默认情况下，`as_json()` 不会转义其输出。如果你使用它来处理类似 AJAX 请求的表单视图，客户端解释响应并将错误插入到页面中，你会希望确保在客户端转义结果，以避免跨站点脚本攻击的可能性。你可以在 JavaScript 中使用 `element.textContent = errorText` 或者使用 jQuery 的 `$(el).text(errorText)` （而不是它的 `.html()` 函数）来实现。

如果出于某些原因你不想使用客户端转义，你也可以设置 `escape_html=True`，错误信息将被转义，这样你就可以直接在 HTML 中使用它们。

Form.errors.get_json_data(escape_html=False)

Returns the errors as a dictionary suitable for serializing to JSON. `Form.errors.as_json()` returns serialized JSON, while this returns the error data before it's serialized.

The `escape_html` parameter behaves as described in `Form.errors.as_json()`.

Form.add_error(field, error)

该方法允许在 `Form.clean()` 方法中添加错误到特定字段，或者从表单外部添加错误，例如从视图中添加。

`field` 参数是应该添加错误的字段名。如果它的值是 `None`，错误将被视为非字段错误，就像 `Form.non_field_errors()` 返回的那样。

`error` 参数可以是一个字符串，或者最好是 `ValidationError` 的实例。关于定义表单错误的最佳做法，请参见 引发 ValidationError。

注意，`Form.add_error()` 会自动从 `cleaned_data` 中删除相关字段。

Form.has_error(field, code=None)

本方法返回一个布尔值，表示一个字段是否有特定错误 `code` 的错误。如果 `code` 是 `None`，如果字段包含任何错误，它将返回 `True`。

要检查非字段错误，使用 `NON_FIELD_ERRORS` 作为 `field` 参数。

Form.non_field_errors()

这个方法从 `Form.errors` 中返回没有与特定字段关联的错误列表。这包括在 `Form.clean()` 中引发的 `ValidationError` 和使用 `Form.add_error(None, "...")` 添加的错误。

### 非绑定表单的行为

对于没有数据的表单进行验证是没有意义的，但是为了记录，以下是未绑定表单的情况：

    >>> f = ContactForm()
    >>> f.is_valid()
    False
    >>> f.errors
    {}

## 初始表单值

Form.initial

使用 `initial` 在运行时声明表单字段的初始值。例如，你可能想用当前会话的用户名来填写 `username` 字段。

要实现这一点，可以使用 `initial` 参数来设置 `Form` 的初始值。如果提供了该参数，它应该是一个将字段名称映射到初始值的字典。只需要包括要指定初始值的字段，不需要包括表单中的每个字段。例如：

    >>> f = ContactForm(initial={"subject": "Hi there!"})

这些值只对未绑定的表单显示，如果没有提供特定的值，它们不会被用作后备值。

如果一个 `Field` 定义了 `initial`，并且在实例化表单时包括了 `initial`，那么后者的 `initial` 会具有优先权。在这个示例中，`initial` 在字段级别和表单实例级别都提供了，后者优先：

    >>> from django import forms
    >>> class CommentForm(forms.Form):
    ...     name = forms.CharField(initial="class")
    ...     url = forms.URLField()
    ...     comment = forms.CharField()
    ...
    >>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
    >>> print(f)
    <div>Name:<input type="text" name="name" value="instance" required></div>
    <div>Url:<input type="url" name="url" required></div>
    <div>Comment:<input type="text" name="comment" required></div>

Form.get_initial_for_field(field, field_name)

返回一个表单字段的初始数据。如果存在的话，它从 `Form.initial` 检索数据，否则尝试 `Field.initial`。可调用的值将被执行。

It is recommended to use `BoundField.initial` over `get_initial_for_field()` because `BoundField.initial` has a simpler interface. Also, unlike `get_initial_for_field()`, `BoundField.initial` caches its values. This is useful especially when dealing with callables whose return values can change (e.g. `datetime.now` or `uuid.uuid4`):

    >>> import uuid
    >>> class UUIDCommentForm(CommentForm):
    ...     identifier = forms.UUIDField(initial=uuid.uuid4)
    ...
    >>> f = UUIDCommentForm()
    >>> f.get_initial_for_field(f.fields["identifier"], "identifier")
    UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
    >>> f.get_initial_for_field(f.fields["identifier"], "identifier")
    UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
    >>> # Using BoundField.initial, for comparison
    >>> f["identifier"].initial
    UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
    >>> f["identifier"].initial
    UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')

## 检查哪些表格数据已经改变

Form.has_changed()

当你需要检查表单数据是否与初始数据发生变化时，请使用 `has_changed()` 方法。

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data, initial=data)
    >>> f.has_changed()
    False

当表单提交后，我们会重新构建表单，并提供原始数据，以便进行对比。

    >>> f = ContactForm(request.POST, initial=data)
    >>> f.has_changed()

如果来自 `request.POST` 的数据与 `initial` 中提供的数据不同，那么 `has_changed()` 将为 `True`，否则为 `False`。结果是通过调用 `Field.has_changed()` 对表单中的每个字段进行计算。

Form.changed_data

`changed_data` 属性返回表单绑定数据（通常是 `request.POST`）中与 `initial` 中提供的数据不同的字段名列表。如果没有不同的数据，则返回一个空列表。

    >>> f = ContactForm(request.POST, initial=data)
    >>> if f.has_changed():
    ...     print("The following fields changed: %s" % ", ".join(f.changed_data))
    ...
    >>> f.changed_data
    ['subject', 'message']

## 访问表单中的字段

Form.fields

您可以通过表单实例的 `fields` 属性访问 `Form` 的字段：

    >>> for row in f.fields.values():
    ...     print(row)
    ...
    <django.forms.fields.CharField object at 0x7ffaac632510>
    <django.forms.fields.URLField object at 0x7ffaac632f90>
    <django.forms.fields.CharField object at 0x7ffaac3aa050>
    >>> f.fields["name"]
    <django.forms.fields.CharField object at 0x7ffaac6324d0>

您可以更改 `Form` 实例的字段和 `BoundField`，以改变它在表单中的呈现方式：

    >>> f.as_div().split("</div>")[0]
    '<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
    >>> f["subject"].label = "Topic"
    >>> f.as_div().split("</div>")[0]
    '<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

小心不要修改 `base_fields` 属性，因为这种修改会影响到同一个 Python 进程中所有后续的 `ContactForm` 实例：

    >>> f.base_fields["subject"].label_suffix = "?"
    >>> another_f = ContactForm(auto_id=False)
    >>> another_f.as_div().split("</div>")[0]
    '<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

## 访问“干净的”数据

Form.cleaned_data

`Form` 类中的每个字段不仅负责验证数据，还负责“清理”数据——将其规范为一致的格式。这是一个很好的功能，因为它允许以各种方式输入特定字段的数据，并总是产生一致的输出。

例如， `DateField` 将输入规范化为 Python 的 `datetime.date` 对象。无论你传递给它的是格式为 `'1994-07-15'` 的字符串，还是 `datetime.date` 对象，或者其他一些格式，只要它是有效的，`DateField` 都会将它规范化为 `datetime.date` 对象。

一旦你创建了一个带有一组数据并进行了验证的 `Form` 实例，你可以通过它的 `cleaned_data` 属性访问清洁后的数据：

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    True
    >>> f.cleaned_data
    {'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}

请注意，任何基于文本的字段——如 `CharField` 或 `EmailField`——总是将输入清理成一个字符串。我们将在本文档后面介绍编码的含义。

如果你的数据验证不通过，`cleaned_data` 字典仅包含有效的字段：

    >>> data = {
    ...     "subject": "",
    ...     "message": "Hi there",
    ...     "sender": "invalid email address",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    False
    >>> f.cleaned_data
    {'cc_myself': True, 'message': 'Hi there'}

`cleaned_data` 将始终仅包含在 `Form` 中定义的字段的键，即使在定义 `Form` 时传递了额外的数据。在这个例子中，我们在 `ContactForm` 构造函数中传递了许多额外字段，但 `cleaned_data` 仅包含表单的字段：

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ...     "extra_field_1": "foo",
    ...     "extra_field_2": "bar",
    ...     "extra_field_3": "baz",
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    True
    >>> f.cleaned_data  # Doesn't contain extra_field_1, etc.
    {'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}

当 `Form` 有效时，即使数据中没有为一些可选字段提供值，`cleaned_data` 也会包括所有字段的键和值。在这个例子中，数据字典没有包含 `nick_name` 字段的值，但 `cleaned_data` 包括它，并带有一个空值：

    >>> from django import forms
    >>> class OptionalPersonForm(forms.Form):
    ...     first_name = forms.CharField()
    ...     last_name = forms.CharField()
    ...     nick_name = forms.CharField(required=False)
    ...
    >>> data = {"first_name": "John", "last_name": "Lennon"}
    >>> f = OptionalPersonForm(data)
    >>> f.is_valid()
    True
    >>> f.cleaned_data
    {'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}

In this above example, the `cleaned_data` value for `nick_name` is set to an empty string, because `nick_name` is `CharField`, and `CharField`s treat empty values as an empty string. Each field type knows what its "blank" value is -- e.g., for `DateField`, it's `None` instead of the empty string. For full details on each field's behavior in this case, see the "Empty value" note for each field in the 内置 Field 类 section below.

你可以编写代码来对特定的表单字段（基于其名称）或整个表单（考虑各种字段的组合）进行验证。更多关于这方面的信息请参见 表单和字段验证。

## 将表单输出为 HTML

一个 `Form` 对象的第二个任务是将自己呈现为 HTML。要做到这一点，只需将它打印出来：

    >>> f = ContactForm()
    >>> print(f)
    <div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject"></div>
    <div><label for="id_message">Message:</label><input type="text" name="message" required id="id_message"></div>
    <div><label for="id_sender">Sender:</label><input type="email" name="sender" required id="id_sender"></div>
    <div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself"></div>

如果表单与数据绑定，HTML 输出将适当地包含该数据。例如，如果一个字段由 `<input type="text">` 表示，数据将位于 `value` 属性中。如果一个字段由 `<input type="checkbox">` 表示，那么 HTML 中将包含 `checked` （如果适用）：

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ... }
    >>> f = ContactForm(data)
    >>> print(f)
    <div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
    <div><label for="id_message">Message:</label><input type="text" name="message" value="Hi there" required id="id_message"></div>
    <div><label for="id_sender">Sender:</label><input type="email" name="sender" value="foo@example.com" required id="id_sender"></div>
    <div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></div>

这个默认输出会使用 `<div>` 包装每个字段。请注意以下内容：

- 为了灵活性，输出 不包括 `<form>` 和 `</form>` 标签，以及 `<input type="submit">` 标签。这部分工作需要由你来完成。

- 每个字段类型都有一个默认的 HTML 表示。`CharField` 用 `<input type="text">` 表示，`EmailField` 用 `<input type="email">` 表示。`BooleanField(null=False)` 由一个 `<input type="checkbox">`。请注意，这些只是合理的默认值；你可以通过使用部件来指定一个给定字段使用的 HTML，我们将在后面解释。

- 每个标签的 HTML `name` 直接从 `ContactForm` 类中的属性名中提取。

- 每个字段的文本标签——例如 `'Subject:'`、`'Message:'` 和 `'Cc myself:'`，是根据字段名将所有下划线转换为空格并将第一个字母大写而产生的。同样，请注意这些只是合理的默认值；你也可以手动指定标签。

- 每个文本标签都被一个 HTML `<label>` 标签包围，该标签通过其 `id` 指向相应的表格字段。而它的 `id` 则是通过在字段名前加上 `'id_'` 生成的。`id` 属性和 `<label>` 标签默认包含在输出中，以遵循最佳实践，但你可以改变这种行为。

- 输出使用 HTML5 语法，目标是 `<!DOCTYPE html>`。例如，它使用布尔属性，如 `checked` 而不是 XHTML 风格的 `checked='checked'`。

虽然 `<div>` 输出是在打印表单时的默认输出样式，但你可以通过使用自己的表单模板来自定义输出，这可以在整个站点范围、每个表单或每个实例中进行设置。请参阅 可复用的表单模板。

### 默认渲染

当你打印一个表单时，默认的渲染使用以下方法和属性。

#### `template_name`

Form.template_name

如果表单被转换为字符串，例如通过 `print(form)` 或在模板中通过 `{{ form }}`，则渲染的模板名称。

默认情况下，它返回渲染器的 `form_template_name` 的值。你可以将其设置为一个字符串模板名称，以便在特定的表单类中进行覆盖。

#### `render()`

Form.render(template_name=None, context=None, renderer=None)

render 方法会被 `__str__` 方法调用，同时也被 `Form.as_div()`、`Form.as_table()`、`Form.as_p()` 和 `Form.as_ul()` 方法调用。所有参数都是可选的，默认值为：

- `template_name`： `Form.template_name`

- `context`：由 `Form.get_context()` 返回的值

- `renderer`： 由 `Form.default_renderer` 返回的值

通过传递 `template_name`，你可以自定义仅用于单个调用的模板。

#### `get_context()`

Form.get_context()

返回用于渲染表单的模板上下文。

可用的上下文：

- `form`: 绑定表单。

- `fields`： 所有绑定字段，除了隐藏字段。

- `hidden_fields`： 所有隐藏的绑定字段。

- `errors`： 所有与字段无关的或与隐藏字段有关的表单错误。

#### `template_name_label`

Form.template_name_label

用于渲染字段的 `<label>` 的模板，当调用 `BoundField.label_tag()`/`legend_tag()` 时使用。可以通过覆盖此属性来更改每个表单的模板，也可以通过覆盖默认模板来更一般地更改，参见 覆盖内置表单模板。

### 输出样式

更改表单输出样式的推荐方法是设置自定义表单模板，可以是整个站点范围、每个表单或每个实例。有关示例，请参阅 可复用的表单模板。

以下的辅助函数是为了向后兼容而提供的，它们是对 `Form.render()` 的代理，传递了特定的 `template_name` 值。

Note

在框架提供的模板和输出样式中，推荐使用默认的 `as_div()` 而不是 `as_p()`、`as_table()` 和 `as_ul()` 版本，因为该模板实现了 `<fieldset>` 和 `<legend>` 来组合相关的输入，对于使用屏幕阅读器的用户更容易导航。

每个辅助函数将一个表单方法与一个给出适当模板名称的属性配对。

#### `as_div()`

Form.template_name_div

`as_div()` 使用的模板。默认值：`'django/forms/div.html'`。

Form.as_div()

`as_div()` 将表单呈现为一系列 `<div>` 元素，每个 `<div>` 包含一个字段，例如：

    >>> f = ContactForm()
    >>> f.as_div()

...生成的 HTML 如下：

    <div>
    <label for="id_subject">Subject:</label>
    <input type="text" name="subject" maxlength="100" required id="id_subject">
    </div>
    <div>
    <label for="id_message">Message:</label>
    <input type="text" name="message" required id="id_message">
    </div>
    <div>
    <label for="id_sender">Sender:</label>
    <input type="email" name="sender" required id="id_sender">
    </div>
    <div>
    <label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself">
    </div>

#### `as_p()`

Form.template_name_p

由 `as_p()` 使用的模板。默认值为 `'django/forms/p.html'`。

Form.as_p()

`as_p()` 将表单呈现为一系列 `<p>` 标签，每个 `<p>` 包含一个字段：

    >>> f = ContactForm()
    >>> f.as_p()
    '<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>'
    >>> print(f.as_p())
    <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
    <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>
    <p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p>
    <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>

#### `as_ul()`

Form.template_name_ul

由 `as_ul()` 使用的模板。默认值为 `'django/forms/ul.html'`。

Form.as_ul()

`as_ul()` 将表单呈现为一系列 `<li>` 标签，每个 `<li>` 包含一个字段。它不包括 `<ul>` 或 `</ul>`，这样你可以在 `<ul>` 上指定任何HTML属性以增加灵活性：

    >>> f = ContactForm()
    >>> f.as_ul()
    '<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>'
    >>> print(f.as_ul())
    <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>
    <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>
    <li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>
    <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>

#### `as_table()`

Form.template_name_table

由 `as_table()` 使用的模板。默认值为 `'django/forms/table.html'`。

Form.as_table()

`as_table()` 将表单呈现为 HTML 的 `<table>`：

    >>> f = ContactForm()
    >>> f.as_table()
    '<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>'
    >>> print(f.as_table())
    <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
    <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
    <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
    <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>

### 样式化必填或错误的表单行

Form.error_css_class

Form.required_css_class

对必填或有错误的表单行和字段进行样式设计是很常见的。例如，你可能想用粗体显示必填的表格行，用红色突出显示错误。

`Form` 类有几个钩子，你可以用来给必填行或有错误的行添加 `class` 属性：设置 `Form.error_css_class` 和／或 `Form.required_css_class` 属性：

    from django import forms

    class ContactForm(forms.Form):
        error_css_class = "error"
        required_css_class = "required"

        # ... and the rest of your fields here

一旦你这样做了，行将根据需要被赋予 `"error"` 和/或 `"required"` 类。HTML 将类似于：

    >>> f = ContactForm(data)
    >>> print(f)
    <div class="required"><label for="id_subject" class="required">Subject:</label> ...
    <div class="required"><label for="id_message" class="required">Message:</label> ...
    <div class="required"><label for="id_sender" class="required">Sender:</label> ...
    <div><label for="id_cc_myself">Cc myself:</label> ...
    >>> f["subject"].label_tag()
    <label class="required" for="id_subject">Subject:</label>
    >>> f["subject"].legend_tag()
    <legend class="required" for="id_subject">Subject:</legend>
    >>> f["subject"].label_tag(attrs={"class": "foo"})
    <label for="id_subject" class="foo required">Subject:</label>
    >>> 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 custom BoundField.

### 设置表单元素的 HTML `id` 属性和 `<label>` 标签。

Form.auto_id

默认情况下，表单渲染方法包括：

- 表单元素的 HTML `id` 属性。

- 标签周围对应的 `<label>` 标签。HTML `<label>` 标签指定了哪个标签文本与哪个表单元素相关联。这个小小的改进使表单更加可用，也更容易被辅助设备访问。使用 `<label>` 标签总是一个好主意。

The `id` attribute values are generated by prepending `id_` to the form field names. This behavior is configurable, though, if you want to change the `id` convention or remove HTML `id` attributes and `<label>` tags entirely.

使用 `Form` 构造函数的 `auto_id` 参数来控制 `id` 和标签行为。这个参数必须是 `True`、`False` 或一个字符串。

如果 `auto_id` 是 `False`，那么表单输出将不包含 `<label>` 标签和 `id` 属性：

    >>> f = ContactForm(auto_id=False)
    >>> print(f)
    <div>Subject:<input type="text" name="subject" maxlength="100" required></div>
    <div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
    <div>Sender:<input type="email" name="sender" required></div>
    <div>Cc myself:<input type="checkbox" name="cc_myself"></div>

如果 `auto_id` 设置为 `True`，那么表单输出将包含 `<label>` 标签，并且将使用字段名作为每个表单字段的 `id`：

    >>> f = ContactForm(auto_id=True)
    >>> print(f)
    <div><label for="subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="subject"></div>
    <div><label for="message">Message:</label><textarea name="message" cols="40" rows="10" required id="message"></textarea></div>
    <div><label for="sender">Sender:</label><input type="email" name="sender" required id="sender"></div>
    <div><label for="cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="cc_myself"></div>

如果 `auto_id` 设置为包含格式字符 `'%s'` 的字符串，那么表单输出将包含 `<label>` 标签，并且将根据格式字符串生成 `id` 属性。例如，对于格式字符串 `'field_%s'`，名为 `subject` 的字段将获得 `id` 值 `'field_subject'`。继续我们的例子：

    >>> f = ContactForm(auto_id="id_for_%s")
    >>> print(f)
    <div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
    <div><label for="id_for_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
    <div><label for="id_for_sender">Sender:</label><input type="email" name="sender" required id="id_for_sender"></div>
    <div><label for="id_for_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>

如果 `auto_id` 被设置为任何其他的真值——比如一个不包含 `%s` 的字符串——那么该库就会像 `auto_id` 是 `True` 一样。

默认情况下，`auto_id` 被设置为字符串 `'id_%s'`。

Form.label_suffix

一个可翻译的字符串（英文默认为冒号（`:`）），将在渲染表格时附加在任何标签名称之后。

可以使用 `label_suffix` 参数自定义该字符，或完全省略它：

    >>> f = ContactForm(auto_id="id_for_%s", label_suffix="")
    >>> print(f)
    <div><label for="id_for_subject">Subject</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
    <div><label for="id_for_message">Message</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
    <div><label for="id_for_sender">Sender</label><input type="email" name="sender" required id="id_for_sender"></div>
    <div><label for="id_for_cc_myself">Cc myself</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
    >>> f = ContactForm(auto_id="id_for_%s", label_suffix=" ->")
    >>> print(f)
    <div><label for="id_for_subject">Subject -&gt;</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
    <div><label for="id_for_message">Message -&gt;</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
    <div><label for="id_for_sender">Sender -&gt;</label><input type="email" name="sender" required id="id_for_sender"></div>
    <div><label for="id_for_cc_myself">Cc myself -&gt;</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>

请注意，只有当标签的最后一个字符不是标点符号时，才会加上标签后缀（在英文中，这些字符是 `.`、`!`、`?` 或 `:`）。

字段还可以定义自己的 `label_suffix`。这将优先于 `Form.label_suffix`。后缀也可以在运行时使用 `label_suffix` 参数来覆盖 `label_tag()`/ `legend_tag()`。

Form.use_required_attribute

当设置为 `True` （默认）时，必填表单字段将有 `required` HTML 属性。

表单集 实例化表单时使用 `use_required_attribute=False` 以避免从表单集中添加和删除表单时浏览器验证错误。

### 设置表单组件的渲染方式

Form.default_renderer

Specifies the renderer to use for the form. Defaults to `None` which means to use the default renderer specified by the `FORM_RENDERER` setting.

你可以在声明你的表单时将其设置为一个类属性，或者使用 `Form.__init__()` 的 `renderer` 参数。例如：

    from django import forms

    class MyForm(forms.Form):
        default_renderer = MyRenderer()

或者：

    form = MyForm(renderer=MyRenderer())

### 字段顺序的注意事项

在 `as_p()`、`as_ul()` 和 `as_table()` 快捷方式中，字段是按照你在表单类中定义的顺序显示的。例如，在 `ContactForm` 的例子中，字段是按照 `subject`、`message`、`sender`、`cc_myself` 的顺序定义的。要调整 HTML 输出的顺序，改变这些字段在类中的排列顺序。

还有其他几种方式可以自定义顺序：

Form.field_order

默认情况下 `Form.field_order=None`，它保留了你在表单类中定义字段的顺序。如果 `field_order` 是一个字段名的列表，则字段按列表指定的顺序排列，其余字段按默认顺序追加。列表中未知的字段名将被忽略。这使得在子类中可以通过将字段设置为 `None` 来禁用字段，而不必重新定义排序。

你也可以使用 `Form` 的 `Form.field_order` 参数来覆盖字段顺序。如果一个 `Form` 定义了 `field_order`，并且 你在实例化 `Form` 时包含了 `field_order`，那么后者的 `field_order` 将具有优先权。

Form.order_fields(field_order)

你可以在任何时候使用 `order_fields()` 对字段进行重新排列，字段名列表如 `field_order`。

### 如何显示错误

If you render a bound `Form` object, the act of rendering will automatically run the form's validation if it hasn't already happened, and the HTML output will include the validation errors as a `<ul class="errorlist">`.

The following:

    >>> data = {
    ...     "subject": "",
    ...     "message": "Hi there",
    ...     "sender": "invalid email address",
    ...     "cc_myself": True,
    ... }
    >>> ContactForm(data).as_div()

...生成的 HTML 如下：

    <div>
      <label for="id_subject">Subject:</label>
      <ul class="errorlist" id="id_subject_error"><li>This field is required.</li></ul>
      <input type="text" name="subject" maxlength="100" required aria-invalid="true" aria-describedby="id_subject_error" id="id_subject">
    </div>
    <div>
      <label for="id_message">Message:</label>
      <textarea name="message" cols="40" rows="10" required id="id_message">Hi there</textarea>
    </div>
    <div>
      <label for="id_sender">Sender:</label>
      <ul class="errorlist" id="id_sender_error"><li>Enter a valid email address.</li></ul>
      <input type="email" name="sender" value="invalid email address" maxlength="320" required aria-invalid="true" aria-describedby="id_sender_error" id="id_sender">
    </div>
    <div>
        <label for="id_cc_myself">Cc myself:</label>
        <input type="checkbox" name="cc_myself" id="id_cc_myself" checked>
    </div>

Django's default form templates will associate validation errors with their input by using the `aria-describedby` HTML attribute when the field has an `auto_id` and a custom `aria-describedby` is not provided. If a custom `aria-describedby` is set when defining the widget this will override the default value.

If the widget is rendered in a `<fieldset>` then `aria-describedby` is added to this element, otherwise it is added to the widget's HTML element (e.g. `<input>`).

Changed in Django 5.2:

`aria-describedby` was added to associate errors with its input.

### 自定义错误列表格式

class ErrorList(initlist=None, error_class=None, renderer=None, field_id=None)

  默认情况下，表单使用 `django.forms.utils.ErrorList` 来格式化验证错误。`ErrorList` 是一个类似列表的对象，其中 `initlist` 是错误列表。此外，这个类有以下属性和方法。

  Changed in Django 5.2:

  The `field_id` argument was added.

  error_class

    渲染错误列表时要使用的 CSS 类。任何提供的类将被添加到默认的 `errorlist` 类中。

  renderer

    Specifies the renderer to use for `ErrorList`. Defaults to `None` which means to use the default renderer specified by the `FORM_RENDERER` setting.

  field_id
    New in Django 5.2.

    An `id` for the field for which the errors relate. This allows an HTML `id` attribute to be added in the error template and is useful to associate the errors with the field. The default template uses the format `id="{{ field_id }}_error"` and a value is provided by `Form.add_error()` using the field's `auto_id`.

  template_name

    调用 `__str__` 或 `render()` 时使用的模板名称。默认情况下，这是 `'django/forms/errors/list/default.html'`，它是 `'ul.html'` 模板的代理。

  template_name_text

    调用 `as_text()` 时使用的模板名称。默认是 `'django/forms/errors/list/text.html'`。该模板将错误显示为一个列表，其中包含了一些要点。

  template_name_ul

    调用 `as_ul()` 时使用的模板名称。默认情况下，这是 `'django/forms/errors/list/ul.html'`。这个模板在 `<li>` 标签中渲染错误，并使用 `error_class` 所定义的 CSS 类来包装 `<ul>`。

  get_context()

    返回模板中渲染错误的上下文。

    可用的上下文：

    - `errors`： 一个错误列表。

    - `error_class`：一个 CSS 类的字符串。

  render(template_name=None, context=None, renderer=None)

    渲染方法被 `__str__` 以及 `as_ul()` 方法所调用。

    所有参数都是可选的，将默认为：

    - `template_name`：由 `template_name` 返回的值。

    - `context`： 由 `get_context()` 返回的值

    - `renderer`： 由 `renderer` 返回的值

  as_text()

    使用由 `template_name_text` 定义的模板渲染错误列表。

  as_ul()

    使用由 `template_name_ul` 定义的模板渲染错误列表。

  如果你想自定义错误的渲染，这可以通过覆盖 `template_name` 属性来实现，或者更普遍地通过覆盖默认模板来实现，也可以参见 覆盖内置表单模板。

## 更精细的输出

`as_p()`、`as_ul()` 和 `as_table()` 方法都是快捷方式——它们并不是显示表单对象的唯一方式。

class BoundField

  用于显示 `Form` 实例的单个字段的 HTML 或访问属性。

  该对象的 `__str__()` 方法显示该字段的 HTML。

  You can use `Form.bound_field_class` and `Field.bound_field_class` to specify a different `BoundField` class per form or per field, respectively.

  See 自定义 BoundField for examples of overriding a `BoundField`.

要检索单个 `BoundField`，可以在表单上使用字段的名称作为键进行字典查找：

    >>> form = ContactForm()
    >>> print(form["subject"])
    <input id="id_subject" type="text" name="subject" maxlength="100" required>

要检索所有的 `BoundField` 对象，可以迭代表单：

    >>> form = ContactForm()
    >>> for boundfield in form:
    ...     print(boundfield)
    ...
    <input id="id_subject" type="text" name="subject" maxlength="100" required>
    <input type="text" name="message" id="id_message" required>
    <input type="email" name="sender" id="id_sender" required>
    <input type="checkbox" name="cc_myself" id="id_cc_myself">

字段特定的输出遵循表单对象的 `auto_id` 设置：

    >>> f = ContactForm(auto_id=False)
    >>> print(f["message"])
    <input type="text" name="message" required>
    >>> f = ContactForm(auto_id="id_%s")
    >>> print(f["message"])
    <input type="text" name="message" id="id_message" required>

### `BoundField` 的属性

BoundField.aria_describedby
  New in Django 5.2.

  Returns an `aria-describedby` reference to associate a field with its help text and errors. Returns `None` if `aria-describedby` is set in `Widget.attrs` to preserve the user defined attribute when rendering the form.

BoundField.auto_id

  `BoundField` 的 HTML ID 属性。如果 `Form.auto_id` 是 `False`，则返回一个空字符串。

BoundField.data

  该属性返回由 widget 的 `value_from_datadict()` 方法提取的这个 `BoundField` 的数据，如果没有提供数据则返回 `None`：

      >>> unbound_form = ContactForm()
      >>> print(unbound_form["subject"].data)
      None
      >>> bound_form = ContactForm(data={"subject": "My Subject"})
      >>> print(bound_form["subject"].data)
      My Subject

BoundField.errors

  一个 类似列表的对象，在打印时显示为 HTML `<ul class="errorlist">`：

      >>> data = {"subject": "hi", "message": "", "sender": "", "cc_myself": ""}
      >>> f = ContactForm(data, auto_id=False)
      >>> print(f["message"])
      <input type="text" name="message" required aria-invalid="true">
      >>> f["message"].errors
      ['This field is required.']
      >>> print(f["message"].errors)
      <ul class="errorlist"><li>This field is required.</li></ul>
      >>> f["subject"].errors
      []
      >>> print(f["subject"].errors)

      >>> str(f["subject"].errors)
      ''

  当渲染带有错误的字段时，将在字段的小部件上设置 `aria-invalid="true"`，以向屏幕阅读器用户指示存在错误。

BoundField.field

  这个 `Field` 封装的表单类中的表单 `BoundField` 实例。

BoundField.form

  这个 `Form` 实例与这个 `BoundField` 绑定。

BoundField.help_text

  字段的 `help_text`。

BoundField.html_name

  部件的 HTML `name` 属性中使用的名称。它考虑到了 `prefix` 的形式。

BoundField.id_for_label

  使用这个属性来渲染该字段的 ID。例如，如果你在模板中手动构造一个 `<label>` （尽管 `label_tag()`/`legend_tag()` 会为你执行此操作）：

      <label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}

  默认情况下，这将是字段的名称，前缀为 `id_` （上面的例子为 "`id_my_field`"）。你可以通过设置 `attrs` 对字段的部件进行修改。例如，声明一个字段是这样的：

      my_field = forms.CharField(widget=forms.TextInput(attrs={"id": "myFIELD"}))

  并使用上面的模板，会呈现出这样的效果：

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

BoundField.initial

  使用 `BoundField.initial` 来检索一个表单字段的初始数据。如果存在，它从 `Form.initial` 检索数据，否则尝试 `Field.initial`。值为可调用对象将被执行。参见 初始表单值 获取更多的例子。

  `BoundField.initial` 缓存其返回值，这在处理可调用对象的情况下特别有用，其返回值可能会改变（例如，`datetime.now` 或 `uuid.uuid4`）：

      >>> from datetime import datetime
      >>> class DatedCommentForm(CommentForm):
      ...     created = forms.DateTimeField(initial=datetime.now)
      ...
      >>> f = DatedCommentForm()
      >>> f["created"].initial
      datetime.datetime(2021, 7, 27, 9, 5, 54)
      >>> f["created"].initial
      datetime.datetime(2021, 7, 27, 9, 5, 54)

  Using `BoundField.initial` is recommended over `get_initial_for_field()`.

BoundField.is_hidden

  如果这个 `BoundField` 的部件被隐藏，返回 `True`。

BoundField.label

  字段的 `label`。这在 `label_tag()`/`legend_tag()` 中使用。

BoundField.name

  该字段在表单中的名称：

      >>> f = ContactForm()
      >>> print(f["subject"].name)
      subject
      >>> print(f["message"].name)
      message

BoundField.template_name

  使用 `BoundField.as_field_group()` 渲染的模板的名称。

  如果设置了 `template_name`，则返回该值，否则返回 `field_template_name` 的值的属性。

BoundField.use_fieldset

  返回该 BoundField widget 的 `use_fieldset` 属性的值。

BoundField.widget_type

  返回封装字段 widget 的类名的小写形式，去除任何尾随的 `input` 或 `widget`。这可以在构建依赖于 widget 类型的表单时使用。例如：

      {% for field in form %}
          {% if field.widget_type == 'checkbox' %}
              # render one way
          {% else %}
              # render another way
          {% endif %}
      {% endfor %}

### `BoundField` 方法

BoundField.as_field_group()

  使用默认值使用 `BoundField.render()` 渲染字段，渲染 `BoundField`，包括其标签、帮助文本和错误，使用模板的 `template_name` （如果设置）或者使用 `field_template_name`。

BoundField.as_hidden(attrs=None, **kwargs)

  返回将其表示为 `<input type="hidden">` 的 HTML 字符串。

  `**kwargs` 传递给 `as_widget()`。

  这个方法主要在内部使用。你应该使用部件来代替。

BoundField.as_widget(widget=None, attrs=None, only_initial=False)

  Renders the field by rendering the passed widget, adding any HTML attributes passed as `attrs`. If no widget is specified, then the field's default widget will be used.

  `only_initial` 是 Django 内部使用的，不应该明确设置。

BoundField.css_classes(extra_classes=None)

  当你使用 Django 的渲染快捷方式时，CSS 类用于指示必填表单字段或包含错误的字段。如果你手动渲染一个表单，你可以使用 `css_classes` 方法访问这些 CSS 类：

      >>> f = ContactForm(data={"message": ""})
      >>> f["message"].css_classes()
      'required'

  如果你想要提供一些额外的类，除了可能需要的错误和必填类，你可以将这些类作为参数提供：

      >>> f = ContactForm(data={"message": ""})
      >>> f["message"].css_classes("foo bar")
      'foo bar required'

BoundField.get_context()

  返回用于渲染字段的模板上下文。可用的上下文是 `field`，它是绑定字段的实例。

BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None)

  使用 `Form.template_name_label` 指定的模板，为表单字段渲染一个标签。

  可用的上下文：

  - `field`：这个 `BoundField` 的实例。

  - `contents`：默认是 `BoundField.label` 和 `Form.label_suffix` （或者 `Field.label_suffix`, 如果设置的话）的连接字符串。这可以被 `contents` 和 `label_suffix` 参数所覆盖。

  - `attrs`：一个包含 `for`、`Form.required_css_class` 和 `id` 的 `dict`。`id` 是由字段的部件 `attrs` 或 `BoundField.auto_id` 产生的。其他的属性可以由 `attrs` 参数提供。

  - `use_tag`: 一个布尔值，如果标签具有 `id`，则为 `True`。如果为 `False`，默认模板将省略 `tag`。

  - `tag`: 可选的字符串，用于自定义标签，默认为 `label`。

  Tip

  在你的模板中 `field` 是 `BoundField` 的实例。因此 `field.field` 访问 `BoundField.field` 是你声明的字段，例如 `forms.CharField`。

  要单独渲染表单字段的标签标签，可以调用其 `label_tag()` 方法：

      >>> f = ContactForm(data={"message": ""})
      >>> print(f["message"].label_tag())
      <label for="id_message">Message:</label>

  如果你想自定义渲染，这可以通过覆盖 `Form.template_name_label` 属性来实现，或者更普遍地通过覆盖默认模板来实现，也可以参见 覆盖内置表单模板。

BoundField.legend_tag(contents=None, attrs=None, label_suffix=None)

  使用 `tag='legend'` 调用 `label_tag()` 以使用 `<legend>` 标签呈现标签。这在呈现单选按钮和多选框小部件时非常有用，其中 `<legend>` 可能比 `<label>` 更合适。

BoundField.render(template_name=None, context=None, renderer=None)

  渲染方法由 `as_field_group` 调用。所有参数都是可选的，并且默认为：

  - `template_name`: `BoundField.template_name`

  - `context`：由 `BoundField.get_context()` 返回的值。

  - `renderer`： 由 `Form.default_renderer` 返回的值

  通过传递 `template_name`，你可以自定义仅用于单个调用的模板。

BoundField.value()

  使用这个方法来呈现该字段的原始值，就像它由一个 `Widget` 呈现一样：

      >>> initial = {"subject": "welcome"}
      >>> unbound_form = ContactForm(initial=initial)
      >>> bound_form = ContactForm(data={"subject": "hi"}, initial=initial)
      >>> print(unbound_form["subject"].value())
      welcome
      >>> print(bound_form["subject"].value())
      hi

## 自定义 `BoundField`

Form.bound_field_class

New in Django 5.2.

Define a custom `BoundField` class to use when rendering the form. This takes precedence over the project-level `BaseRenderer.bound_field_class` (along with a custom `FORM_RENDERER`), but can be overridden by the field-level `Field.bound_field_class`.

If not defined as a class variable, `bound_field_class` can be set via the `bound_field_class` argument in the `Form` or `Field` constructor.

For compatibility reasons, a custom form field can still override `Field.get_bound_field()` to use a custom class, though any of the previous options are preferred.

You may want to use a custom `BoundField` if you need to access some additional information about a form field in a template and using a subclass of `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:

    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):
        bound_field_class = GPSCoordinatesBoundField

现在你可以在模板中使用 `{{form.coordinates.country }}` 访问国家。

You may also want to customize the default form field template rendering. For example, you can override `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:

    >>> 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:

    >>> 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, `BaseRenderer.bound_field_class` can be defined on a custom `FORM_RENDERER`:

`mysite/renderers.py`

    from django.forms.renderers import DjangoTemplates

    from .forms import CustomBoundField

    class CustomRenderer(DjangoTemplates):
        bound_field_class = CustomBoundField

`settings.py`

    FORM_RENDERER = "mysite.renderers.CustomRenderer"

## 将上传的文件绑定到表单中

处理有 `FileField` 和 `ImageField` 字段的表单比普通表单要复杂一些。

首先，为了上传文件，你需要确保你的 `<form>` 元素正确地将 `enctype` 定义为 `"multipart/form-data"`：

    <form enctype="multipart/form-data" method="post" action="/foo/">

其次，当你使用表单时，你需要绑定文件数据。文件数据与普通表单数据分开处理，所以当你的表单包含一个 `FileField` 和 `ImageField` 时，你需要在绑定表单时指定第二个参数。因此，如果我们扩展我们的 ContactForm 以包括一个名为 `mugshot` 的 `ImageField`，我们需要绑定包含头像图片的文件数据：

    # Bound form with an image field
    >>> from django.core.files.uploadedfile import SimpleUploadedFile
    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "sender": "foo@example.com",
    ...     "cc_myself": True,
    ... }
    >>> file_data = {"mugshot": SimpleUploadedFile("face.jpg", b"file data")}
    >>> f = ContactFormWithMugshot(data, file_data)

在实际应用中，你通常会将 `request.FILES` 指定为文件数据的来源（就像你使用 `request.POST` 作为表单数据的来源一样）：

    # Bound form with an image field, data from the request
    >>> f = ContactFormWithMugshot(request.POST, request.FILES)

构建一个未绑定的表单与以往一样，省略表单数据和文件数据：

    # Unbound form with an image field
    >>> f = ContactFormWithMugshot()

### 多部分表格的测试

Form.is_multipart()

如果你正在编写可重用的视图或模板，你可能事先不知道你的表单是否是多部分表单。`is_multipart()` 方法告诉你是否需要多部分编码来提交表单：

    >>> f = ContactFormWithMugshot()
    >>> f.is_multipart()
    True

下面是一个在模板中使用的示例：

    {% if form.is_multipart %}
        <form enctype="multipart/form-data" method="post" action="/foo/">
    {% else %}
        <form method="post" action="/foo/">
    {% endif %}
    {{ form }}
    </form>

## 子类化表单

如果你有多个共享字段的 `Form` 类，你可以使用子类来消除冗余。

当你将一个自定义的 `Form` 类子类化时，生成的子类将包括父类的所有字段，然后是你在子类中定义的字段。

在这个例子中，`ContactFormWithPriority` 包含了来自 `ContactForm` 的所有字段，以及一个额外的字段 `priority`。`ContactForm` 的字段首先排列：

    >>> class ContactFormWithPriority(ContactForm):
    ...     priority = forms.CharField()
    ...
    >>> f = ContactFormWithPriority(auto_id=False)
    >>> print(f)
    <div>Subject:<input type="text" name="subject" maxlength="100" required></div>
    <div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
    <div>Sender:<input type="email" name="sender" required></div>
    <div>Cc myself:<input type="checkbox" name="cc_myself"></div>
    <div>Priority:<input type="text" name="priority" required></div>

可以子类化多个表单，将表单视为混合类。在这个例子中，`BeatleForm` 分别子类化了 `PersonForm` 和 `InstrumentForm` （按顺序），它的字段列表包括父类的字段：

    >>> from django import forms
    >>> class PersonForm(forms.Form):
    ...     first_name = forms.CharField()
    ...     last_name = forms.CharField()
    ...
    >>> class InstrumentForm(forms.Form):
    ...     instrument = forms.CharField()
    ...
    >>> class BeatleForm(InstrumentForm, PersonForm):
    ...     haircut_type = forms.CharField()
    ...
    >>> b = BeatleForm(auto_id=False)
    >>> print(b)
    <div>First name:<input type="text" name="first_name" required></div>
    <div>Last name:<input type="text" name="last_name" required></div>
    <div>Instrument:<input type="text" name="instrument" required></div>
    <div>Haircut type:<input type="text" name="haircut_type" required></div>

可以通过在子类上将继承自父类的 `Field` 的名称设置为 `None` 来声明性地移除它。例如：

    >>> from django import forms

    >>> class ParentForm(forms.Form):
    ...     name = forms.CharField()
    ...     age = forms.IntegerField()
    ...

    >>> class ChildForm(ParentForm):
    ...     name = None
    ...

    >>> list(ChildForm().fields)
    ['age']

## 表单前缀

Form.prefix

你可以将多个 Django 表单放在同一个 `<form>` 标签内。为每个 `Form` 提供单独的命名空间，可以使用 `prefix` 关键字参数：

    >>> mother = PersonForm(prefix="mother")
    >>> father = PersonForm(prefix="father")
    >>> print(mother)
    <div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
    <div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
    >>> print(father)
    <div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
    <div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>

命名空间也可以在表单类上指定：

    >>> class PersonForm(forms.Form):
    ...     ...
    ...     prefix = "person"
    ...