---
title: "部件"
version: 6.0
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/6.0/ref/forms/widgets/
canonical: https://djangodocs.dev/zh-hans/6.0/ref/forms/widgets/
---
# 部件

部件是 Django 对 HTML 输入元素的表示。部件处理 HTML 的渲染，以及从对应于部件的 GET／POST 字典中提取数据。

内置部件生成的 HTML 使用 HTML5 语法，目标是 `<!DOCTYPE html>`。例如，它使用布尔属性，如 `checked` 而不是 XHTML 风格的 `checked='checked'`。

> **Tip**
>
> 部件不应该与 [表单字段](/zh-hans/6.0/ref/forms/fields/) 混淆。表单字段处理输入验证的逻辑，直接在模板中使用。小组件处理 HTML 表单输入元素在网页上的渲染和原始提交数据的提取。然而，部件确实需要 [分配](#widget-to-field) 到表单字段。

## 指定部件

每当你在表单中指定一个字段时，Django 会使用一个默认的部件来显示数据类型。要想知道哪个字段使用的是哪个部件，请看 [内置 Field 类](/zh-hans/6.0/ref/forms/fields/#built-in-fields) 的文档。

但是，如果你想为一个字段使用不同的部件，你可以在字段定义中使用 [`widget`](/zh-hans/6.0/ref/forms/fields/#django.forms.Field.widget) 参数。例如：

```
from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)
```

这将指定一个带有注释的表单，该表单使用一个较大的 [`Textarea`](#django.forms.Textarea) 部件，而不是默认的 [`TextInput`](#django.forms.TextInput) 部件。

## 为部件设置参数

许多部件都有可选的额外参数；它们可以在字段上定义部件时进行设置。在下面的例子中， [`years`](#django.forms.SelectDateWidget.years) 属性被设置为 [`SelectDateWidget`](#django.forms.SelectDateWidget)：

```
from django import forms

BIRTH_YEAR_CHOICES = ["1980", "1981", "1982"]
FAVORITE_COLORS_CHOICES = {
    "blue": "Blue",
    "green": "Green",
    "black": "Black",
}

class SimpleForm(forms.Form):
    birth_year = forms.DateField(
        widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES)
    )
    favorite_colors = forms.MultipleChoiceField(
        required=False,
        widget=forms.CheckboxSelectMultiple,
        choices=FAVORITE_COLORS_CHOICES,
    )
```

请参阅 [内置部件](#built-in-widgets)，了解更多关于哪些部件可用以及它们接受哪些参数的信息。

## 自定义部件实例

当 Django 将一个部件渲染成 HTML 时，它只渲染了非常少的标记——Django 不会添加类名，或任何其他部件的特定属性。这意味着，例如，所有的 [`TextInput`](#django.forms.TextInput) 部件在你的网页上看起来都是一样的。

有两种方法来定制部件： [每个部件实例](#styling-widget-instances) 和 [每个部件类](#styling-widget-classes)。

### 样式化部件实例

如果你想让一个部件实例看起来与另一个不同，你需要在实例化部件对象并将其分配给表单字段时指定额外的属性（也许还需要在你的 CSS 文件中添加一些规则）。

例如，采取以下表单：

```
from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()
```

此表单将包括用于 name 和 comment 字段的 [`TextInput`](#django.forms.TextInput) 小部件，以及用于 url 字段的 [`URLInput`](#django.forms.URLInput) 小部件。每个都有默认的渲染 —— 没有 CSS 类，没有额外的属性：

```pycon
>>> f = CommentForm(auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" required></div>
<div>Url:<input type="url" name="url" required></div>
<div>Comment:<input type="text" name="comment" required></div>
```

在真实的网页上，你可能想要自定义这些。你可能希望评论的输入元素更大，并且你可能希望 'name' 小部件具有一些特殊的 CSS 类。还可以指定 'type' 属性以使用不同的 HTML5 输入类型。为此，你可以在创建小部件时使用 [`Widget.attrs`](#django.forms.Widget.attrs) 参数：

```
class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={"class": "special"}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={"size": "40"}))
```

你也可以在表单定义中修改一个部件：

```
class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

    name.widget.attrs.update({"class": "special"})
    comment.widget.attrs.update(size="40")
```

或者如果该字段没有直接在表单上声明（比如模型表单字段），可以使用 [`Form.fields`](/zh-hans/6.0/ref/forms/api/#django.forms.Form.fields) 属性：

```
class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["name"].widget.attrs.update({"class": "special"})
        self.fields["comment"].widget.attrs.update(size="40")
```

Django 会将额外的属性包含在渲染的输出中：

```
>>> f = CommentForm(auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" class="special" required></div>
<div>Url:<input type="url" name="url" required></div>
<div>Comment:<input type="text" name="comment" size="40" required></div>
```

你也可以使用 [`attrs`](#django.forms.Widget.attrs) 设置 HTML `id`。参见 [`BoundField.id_for_label`](/zh-hans/6.0/ref/forms/api/#django.forms.BoundField.id_for_label) 的例子。

### 样式化部件类

有了部件，就可以添加静态资源（`css` 和 `javascript`）并更深入地定制它们的外观和行为。

简而言之，你需要对部件进行子类化，并且 [定义一个内部“Media”类](/zh-hans/6.0/topics/forms/media/#assets-as-a-static-definition) 或者 [创建一个"media"属性](/zh-hans/6.0/topics/forms/media/#dynamic-property)。

这些方法涉及到一些高级的 Python 编程，在 [表单静态资源](/zh-hans/6.0/topics/forms/media/) 主题指南中有详细描述。

## 基础部件类

基础部件类 [`Widget`](#django.forms.Widget) 和 [`MultiWidget`](#django.forms.MultiWidget) 被所有的 [内置部件](#built-in-widgets) 子类化，可以作为自定义部件的基础。

### `Widget`

#### `class Widget(attrs=None)`

This abstract class cannot be rendered, but provides the basic attribute
[`attrs`](#django.forms.Widget.attrs). You may also implement or override the
[`render()`](#django.forms.Widget.render) method on custom widgets.

#### `attrs`

包含要在渲染的部件上设置的 HTML 属性的字典。

```pycon
>>> from django import forms
>>> name = forms.TextInput(attrs={"size": 10, "title": "Your name"})
>>> name.render("name", "A name")
'<input title="Your name" type="text" name="name" value="A name" size="10">'
```

如果你将属性赋值为 `True` 或 `False`，它将被渲染为 HTML5 的布尔属性：

```pycon
>>> name = forms.TextInput(attrs={"required": True})
>>> name.render("name", "A name")
'<input name="name" type="text" value="A name" required>'
>>>
>>> name = forms.TextInput(attrs={"required": False})
>>> name.render("name", "A name")
'<input name="name" type="text" value="A name">'
```

#### `supports_microseconds`

属性，默认为 `True`。如果设置为 `False`，则 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 和 [`time`](https://docs.python.org/3/library/datetime.html#datetime.time) 值的微秒部分将被设置为 `0`。

#### `format_value(value)`

清理并返回一个值，供部件模板使用。`value` 并不能保证是有效的输入，因此子类的实现应该是防御性的。

#### `get_context(name, value, attrs)`

返回渲染部件模板时要使用的值的字典。默认情况下，该字典包含一个键，`'widget'`，它是一个包含以下键的部件的字典表示：

- `'name'`：`name` 参数中的字段名称。
- `'is_hidden'`：表示该部件是否被隐藏的布尔值。
- `'required'`：表示该部件是否需要该字段的布尔值。
- `'value'`：[`format_value()`](#django.forms.Widget.format_value) 返回的值。
- `'attrs'`：拟在渲染的部件上设置的 HTML 属性。[`attrs`](#django.forms.Widget.attrs) 属性和 `attrs` 参数的组合。
- `''template_name'`：`self.template_name` 的值。

`Widget` 子类可以通过覆盖该方法提供自定义上下文值。

#### `id_for_label(id_)`

根据字段的 ID 返回此小部件的 HTML ID 属性，供 `<label>` 使用。如果没有可用的 ID，则返回空字符串。

这个钩子是必要的，因为一些部件有多个 HTML 元素，因此有多个 ID。在这种情况下，这个方法应该返回一个与部件标签中第一个 ID 对应的 ID 值。

#### `render(name, value, attrs=None, renderer=None)`

使用给定的渲染器将部件渲染成 HTML。如果 `renderer` 为 `None`，则使用 [`FORM_RENDERER`](/zh-hans/6.0/ref/settings/#std-setting-FORM_RENDERER) 设置中的渲染器。

#### `value_from_datadict(data, files, name)`

给定一个数据字典和这个部件的名称，返回这个部件的值。`files` 可能包含来自 [`request.FILES`](/zh-hans/6.0/ref/request-response/#django.http.HttpRequest.FILES) 的数据。如果没有提供值，则返回 `None`。还需要注意的是，在处理表单数据的过程中，`value_from_datadict` 可能会被调用不止一次，所以如果你自定义它并添加昂贵的处理，你应该自己实现一些缓存机制。

#### `value_omitted_from_data(data, files, name)`

给定 `data` 和 `files` 字典和这个部件的名称，返回该部件是否有数据或文件。

该方法的结果会影响模型表单中的字段 [是否回到默认](/zh-hans/6.0/topics/forms/modelforms/#topics-modelform-save)。

特殊情况有 [`CheckboxInput`](#django.forms.CheckboxInput)、[`CheckboxSelectMultiple`](#django.forms.CheckboxSelectMultiple) 和 [`SelectMultiple`](#django.forms.SelectMultiple)，它们总是返回 `False`，因为未选中的复选框和未选择的 `<select multiple>`，不会出现在 HTML 表单提交的数据中，所以不知道用户是否提交了一个值。

#### `use_fieldset`

一个用于标识小部件在渲染时是否应该分组在一个带有 `<legend>` 的 `<fieldset>` 中的属性。默认为 `False`，但当小部件包含多个 `<input>` 标签时，例如 [`CheckboxSelectMultiple`](#django.forms.CheckboxSelectMultiple)、[`RadioSelect`](#django.forms.RadioSelect)、[`MultiWidget`](#django.forms.MultiWidget)、[`SplitDateTimeWidget`](#django.forms.SplitDateTimeWidget) 和 [`SelectDateWidget`](#django.forms.SelectDateWidget) 时，它为 `True`。

#### `use_required_attribute(initial)`

给定一个表单字段的 `initial` 值，返回是否可以用 `required` HTML 属性来渲染部件。表单使用这个方法与 [`Field.required`](/zh-hans/6.0/ref/forms/fields/#django.forms.Field.required) 和 `Form.use_required_attribute` 一起决定是否为每个字段显示 `required` 属性。

默认情况下，对隐藏的部件返回 `False`，否则返回 `True`。特殊情况是 [`FileInput`](#django.forms.FileInput) 和 [`ClearableFileInput`](#django.forms.ClearableFileInput)，当设置了 `initial` 时，返回 `False`；还有 [`CheckboxSelectMultiple`](#django.forms.CheckboxSelectMultiple)，总是返回 `False`，因为浏览器验证需要选中所有的复选框，而不是至少一个。

Override this method in custom widgets that aren't compatible with
browser validation. For example, a WYSIWYG text editor widget backed by
a hidden `textarea` element may want to always return `False` to
avoid browser validation on the hidden field.

### `MultiWidget`

#### `class MultiWidget(widgets, attrs=None)`

[`MultiWidget`](#django.forms.MultiWidget) 与 [`MultiValueField`](/zh-hans/6.0/ref/forms/fields/#django.forms.MultiValueField) 携手合作。

[`MultiWidget`](#django.forms.MultiWidget) 有一个必要的参数：

#### `widgets`

一个包含所需小部件的可迭代对象。例如：

```pycon
>>> from django.forms import MultiWidget, TextInput
>>> widget = MultiWidget(widgets=[TextInput, TextInput])
>>> widget.render("name", ["john", "paul"])
'<input type="text" name="name_0" value="john"><input type="text" name="name_1" value="paul">'
```

你可以提供一个字典来指定每个子小部件的 `name` 属性的自定义后缀。在这种情况下，对于每个 `(key, widget)` 对，将将 key 添加到小部件的 `name` 中以生成属性值。你可以为一个小部件提供空字符串（`''`），以取消一个小部件的后缀。例如：

```pycon
>>> widget = MultiWidget(widgets={"": TextInput, "last": TextInput})
>>> widget.render("name", ["john", "paul"])
'<input type="text" name="name" value="john"><input type="text" name="name_last" value="paul">'
```

还有一个必要的方法：

#### `decompress(value)`

这个方法从字段中获取一个“压缩”值，然后返回一个“解压缩”值的列表。可以假定输入值有效，但不一定是非空的。

这个方法 **必须由子类实现**，由于值可能是空的，所以实现必须是防御性的。

“解压”背后的原理是，需要将表单字段的组合值“拆分”成每个部件的值。

一个例子是 [`SplitDateTimeWidget`](#django.forms.SplitDateTimeWidget) 如何将一个 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 值变成一个列表，将日期和时间分成两个独立的值：

```
from django.forms import MultiWidget

class SplitDateTimeWidget(MultiWidget):
    # ...

    def decompress(self, value):
        if value:
            return [value.date(), value.time()]
        return [None, None]
```

> **Tip**
>
> 请注意 [`MultiValueField`](/zh-hans/6.0/ref/forms/fields/#django.forms.MultiValueField) 有一个补充方法 [`compress()`](/zh-hans/6.0/ref/forms/fields/#django.forms.MultiValueField.compress)，其职责与之相反——将所有成员字段的清理值合并为一个。

它提供了一些自定义上下文：

#### `get_context(name, value, attrs)`

除了 [`Widget.get_context()`](#django.forms.Widget.get_context) 中描述的 `'widget'` 键之外，`MultiWidget` 还增加了一个 `widget['subwidgets']` 键。

这些可以在部件模板中循环使用：

```html+django
{% for subwidget in widget.subwidgets %}
    {% include subwidget.template_name with widget=subwidget %}
{% endfor %}
```

下面是一个例子，它子类为 [`MultiWidget`](#django.forms.MultiWidget)，用于在不同的选择框中显示日期和年、月、日。这个部件的目的是与 [`DateField`](/zh-hans/6.0/ref/forms/fields/#django.forms.DateField) 而不是 [`MultiValueField`](/zh-hans/6.0/ref/forms/fields/#django.forms.MultiValueField) 一起使用，因此我们实现了 [`value_from_datadict()`](#django.forms.Widget.value_from_datadict)：

```
from datetime import date
from django import forms

class DateSelectorWidget(forms.MultiWidget):
    def __init__(self, attrs=None):
        days = {day: day for day in range(1, 32)}
        months = {month: month for month in range(1, 13)}
        years = {year: year for year in [2018, 2019, 2020]}
        widgets = [
            forms.Select(attrs=attrs, choices=days),
            forms.Select(attrs=attrs, choices=months),
            forms.Select(attrs=attrs, choices=years),
        ]
        super().__init__(widgets, attrs)

    def decompress(self, value):
        if isinstance(value, date):
            return [value.day, value.month, value.year]
        elif isinstance(value, str):
            year, month, day = value.split("-")
            return [day, month, year]
        return [None, None, None]

    def value_from_datadict(self, data, files, name):
        day, month, year = super().value_from_datadict(data, files, name)
        # DateField expects a single string that it can parse into a date.
        return "{}-{}-{}".format(year, month, day)
```

构造函数在一个列表中创建了几个 [`Select`](#django.forms.Select) 部件。`super()` 方法使用这个列表来建立部件。

所需的方法 [`decompress()`](#django.forms.MultiWidget.decompress) 将一个 `datetime.date` 的值分解成对应于每个部件的日、月、年的值。如果选择了一个无效的日期，比如不存在的 2 月 30 日，那么 [`DateField`](/zh-hans/6.0/ref/forms/fields/#django.forms.DateField) 就会把这个方法传给一个字符串代替，所以需要进行解析。最后的 `return` 处理的是 `value` 是 `None` 的时候，也就是说我们的子部件没有任何默认值。

[`value_from_datadict()`](#django.forms.Widget.value_from_datadict) 的默认实现是返回一个与每个 `Widget` 对应的值列表。这在使用 `MultiWidget` 与 `` MultiValueField` `` 时是合适的。但由于我们想将这个部件与一个 [`DateField`](/zh-hans/6.0/ref/forms/fields/#django.forms.DateField) 一起使用，它只取一个值，我们已经覆盖了这个方法。这里的实现将来自子部件的数据组合成一个字符串，其格式为 [`DateField`](/zh-hans/6.0/ref/forms/fields/#django.forms.DateField) 所期望的格式。

## 内置部件

Django 在 `django.forms.widgets` 模块中提供了所有基本的 HTML 部件，以及一些常用的部件组，包括 [文本输入](#text-widgets)、[各种复选框和选择器](#selector-widgets)、[上传文件](#file-upload-widgets) 和 [处理多值输入](#composite-widgets)。

### 处理文本输入的部件

这些部件使用了 HTML 元素 `input` 和 `textarea`。

#### `TextInput`

#### `class TextInput`

- `input_type`：`'text'`
- `template_name`：`'django/forms/widgets/text.html'`
- 渲染为：`<input type="text" ...>`

#### `NumberInput`

#### `class NumberInput`

- `input_type`：`'number'`
- `template_name`：`'django/forms/widgets/number.html'`
- 渲染为：`<input type="number" ...>`

请注意，并不是所有的浏览器都支持在 `number` 输入类型中输入本地化的数字。Django 本身就避免在 [`localize`](/zh-hans/6.0/ref/forms/fields/#django.forms.Field.localize) 属性设置为 `True` 的字段中使用它们。

#### `EmailInput`

#### `class EmailInput`

- `input_type`：`'email'`
- `template_name`：`'django/forms/widgets/email.html'`
- 渲染为：`<input type="email" ...>`

#### `URLInput`

#### `class URLInput`

- `input_type`：`'url'`
- `template_name`：`'django/forms/widgets/url.html'`
- 渲染为：`<input type="url" ...>`

#### `ColorInput`

> **New in Django 5.2**

#### `class ColorInput`

- `input_type`: `'color'`
- `template_name`:`'django/forms/widgets/color.html'`
- Renders as: `<input type="color" ...>`

#### `SearchInput`

> **New in Django 5.2**

#### `class SearchInput`

- `input_type`: `'search'`
- `template_name`: `'django/forms/widgets/search.html'`
- Renders as: `<input type="search" ...>`

#### `TelInput`

> **New in Django 5.2**

#### `class TelInput`

- `input_type`: `'tel'`
- `template_name`: `'django/forms/widgets/tel.html'`
- Renders as: `<input type="tel" ...>`

Browsers perform no client-side validation by default because telephone
number formats vary so much around the world. You can add some by setting
`pattern`, `minlength`, or `maxlength` in the [`Widget.attrs`](#django.forms.Widget.attrs)
argument.

Additionally, you can add server-side validation to your form field with a
validator like [`RegexValidator`](/zh-hans/6.0/ref/validators/#django.core.validators.RegexValidator) or via
third-party packages, such as [django-phonenumber-field](https://pypi.org/project/django-phonenumber-field/).

#### `PasswordInput`

#### `class PasswordInput`

- `input_type`：`'password'`
- `template_name`：`'django/forms/widgets/password.html'`
- 渲染为：`<input type="password" ...>`

需要一个可选的参数：

#### `render_value`

确定当验证错误后重新显示表格时，部件是否会有一个值被填入（默认为 `False`）。

#### `HiddenInput`

#### `class HiddenInput`

- `input_type`：`'hidden'`
- `template_name`：`'django/forms/widgets/hidden.html'`
- 渲染为：`<input type="hidden" ...>`

请注意，还有一个 [`MultipleHiddenInput`](#django.forms.MultipleHiddenInput) 部件，封装了一组隐藏的输入元素。

#### `DateInput`

#### `class DateInput`

- `input_type`：`'text'`
- `template_name`：`'django/forms/widgets/date.html'`
- 渲染为：`<input type="text" ...>`

采用与 [`TextInput`](#django.forms.TextInput) 相同的参数，多一个可选参数：

#### `format`

显示该字段初始值的格式。

如果未提供 `format` 参数，则默认格式是在 [`DATE_INPUT_FORMATS`](/zh-hans/6.0/ref/settings/#std-setting-DATE_INPUT_FORMATS) 中找到的第一个格式，并遵循 [本地格式化](/zh-hans/6.0/topics/i18n/formatting/)。此小部件不支持 `%U`、`%W` 和 `%j` 格式。

> **Using the HTML5 "date" input type**
>
> If you are targeting browsers that support the
> [HTML5 "date" input type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date), you can override the `input_type`
> attribute to enable the browser’s native date picker:
>
> ```
> class MyDateInput(forms.DateInput):
>     input_type = "date"
>     format = "%Y-%m-%d"
> ```
>
> Alternatively:
>
> ```
> DateInput(attrs={"type": "date"}, format="%Y-%m-%d")
> ```
>
> HTML5 date inputs expect values in the ISO format `YYYY-MM-DD`. If a
> different format is provided, the field may appear empty even when a
> value exists. Setting the `format` attribute controls how Django
> provides the value, but the browser controls how it is displayed.
> Hence, the `format` attribute and the [`DATE_INPUT_FORMATS`](/zh-hans/6.0/ref/settings/#std-setting-DATE_INPUT_FORMATS)
> setting will have no effect on the displayed value.

#### `DateTimeInput`

#### `class DateTimeInput`

- `input_type`：`'text'`
- `template_name`：`'django/forms/widgets/datetime.html'`
- 渲染为：`<input type="text" ...>`

采用与 [`TextInput`](#django.forms.TextInput) 相同的参数，多一个可选参数：

#### `format`

显示该字段初始值的格式。

如果未提供 `format` 参数，则默认格式是在 [`DATETIME_INPUT_FORMATS`](/zh-hans/6.0/ref/settings/#std-setting-DATETIME_INPUT_FORMATS) 中找到的第一个格式，并遵循 [本地格式化](/zh-hans/6.0/topics/i18n/formatting/)。此小部件不支持 `%U`、`%W` 和 `%j` 格式。

默认情况下，时间值的微秒部分总是设置为 `0`。如果需要微秒，则使用 [`supports_microseconds`](#django.forms.Widget.supports_microseconds) 属性设置为 `True` 的子类。

#### `TimeInput`

#### `class TimeInput`

- `input_type`：`'text'`
- `template_name`：`'django/forms/widgets/time.html'`
- 渲染为：`<input type="text" ...>`

采用与 [`TextInput`](#django.forms.TextInput) 相同的参数，多一个可选参数：

#### `format`

显示该字段初始值的格式。

如果没有提供 `format` 参数，默认的格式是 [`TIME_INPUT_FORMATS`](/zh-hans/6.0/ref/settings/#std-setting-TIME_INPUT_FORMATS) 中找到的第一种格式，并且尊重 [本地格式化](/zh-hans/6.0/topics/i18n/formatting/)。

关于微秒的处理，请参见 [`DateTimeInput`](#django.forms.DateTimeInput)。

#### `Textarea`

#### `class Textarea`

- `template_name`：`'django/forms/widgets/textarea.html'`
- 渲染为：`<textarea>...</textarea>`

### 选择器和复选框部件

这些部件使用了 HTML 元素 `<select>`、`<input type="checkbox">` 和 `<input type="radio">`。

呈现多个选择的部件有一个 `option_template_name` 属性，指定用于渲染每个选择的模板。例如，对于 [`Select`](#django.forms.Select) 部件，`select_option.html` 会为  `<select>` 渲染 `<option>`。

#### `CheckboxInput`

#### `class CheckboxInput`

- `input_type`：`'checkbox'`
- `template_name`：`'django/forms/widgets/checkbox.html'`
- 渲染为：`<input type="checkbox" ...>`

需要一个可选的参数：

#### `check_test`

一个可调用对象，它接受 `CheckboxInput` 的值，并返回 `True`，如果该复选框应检查该值。

#### `Select`

#### `class Select`

- `template_name`：`'django/forms/widgets/select.html'`
- `option_template_name`：`'django/forms/widgets/select_option.html'`
- 渲染为：`<select><option ...>...</select>`

#### `choices`

当表单字段没有 `choices` 属性时，这个属性是可选的。如果有，当 [`Field`](/zh-hans/6.0/ref/forms/fields/#django.forms.Field) 属性更新时，它将覆盖你在这里设置的任何属性。

#### `NullBooleanSelect`

#### `class NullBooleanSelect`

- `template_name`：`'django/forms/widgets/select.html'`
- `option_template_name`：`'django/forms/widgets/select_option.html'`

选择“未知”、“是”和“否”选项的小组件。

#### `SelectMultiple`

#### `class SelectMultiple`

- `template_name`：`'django/forms/widgets/select.html'`
- `option_template_name`：`'django/forms/widgets/select_option.html'`

类似于 [`Select`](#django.forms.Select)，但允许多选：`<select multiple>...</select>`。

#### `RadioSelect`

#### `class RadioSelect`

- `template_name`：`'django/forms/widgets/radio.html'`
- `option_template_name`：`'django/forms/widgets/radio_option.html'`

类似于 [`Select`](#django.forms.Select)，但在 `<div>` 标签中呈现为一个单选按钮的列表：

```html
<div>
  <div><input type="radio" name="..."></div>
  ...
</div>
```

为了对生成的标记进行更精细的控制，你可以在模板中循环使用单选按钮。假设一个表单 `myform` 有一个字段 `beatles`，使用 `RadioSelect` 作为它的部件。

```html+django
<fieldset>
    <legend>{{ myform.beatles.label }}</legend>
    {% for radio in myform.beatles %}
    <div class="myradio">
        {{ radio }}
    </div>
    {% endfor %}
</fieldset>
```

这将产生以下 HTML：

```html
<fieldset>
    <legend>Radio buttons</legend>
    <div class="myradio">
        <label for="id_beatles_0"><input id="id_beatles_0" name="beatles" type="radio" value="john" required> John</label>
    </div>
    <div class="myradio">
        <label for="id_beatles_1"><input id="id_beatles_1" name="beatles" type="radio" value="paul" required> Paul</label>
    </div>
    <div class="myradio">
        <label for="id_beatles_2"><input id="id_beatles_2" name="beatles" type="radio" value="george" required> George</label>
    </div>
    <div class="myradio">
        <label for="id_beatles_3"><input id="id_beatles_3" name="beatles" type="radio" value="ringo" required> Ringo</label>
    </div>
</fieldset>
```

这包括 `<label>` 标签。为了得到更多的细节，你可以使用每个单选按钮的 `tag`、`choice_label` 和 `id_for_label` 属性。例如，这个模板...

```html+django
<fieldset>
    <legend>{{ myform.beatles.label }}</legend>
    {% for radio in myform.beatles %}
    <label for="{{ radio.id_for_label }}">
        {{ radio.choice_label }}
        <span class="radio">{{ radio.tag }}</span>
    </label>
    {% endfor %}
</fieldset>
```

...将导致以下 HTML：

```html
<fieldset>
    <legend>Radio buttons</legend>
    <label for="id_beatles_0">
        John
        <span class="radio"><input id="id_beatles_0" name="beatles" type="radio" value="john" required></span>
    </label>
    <label for="id_beatles_1">
        Paul
        <span class="radio"><input id="id_beatles_1" name="beatles" type="radio" value="paul" required></span>
    </label>
    <label for="id_beatles_2">
        George
        <span class="radio"><input id="id_beatles_2" name="beatles" type="radio" value="george" required></span>
    </label>
    <label for="id_beatles_3">
        Ringo
        <span class="radio"><input id="id_beatles_3" name="beatles" type="radio" value="ringo" required></span>
    </label>
</fieldset>
```

如果你决定不对单选按钮进行循环处理——例如，如果你的模板包括 `{{ myform.beatles }}` ——它们将在一个 `<div>` 中输出，并带有 `<div>` 标签，如上所述。

外部 `<div>` 容器接收部件的 `id` 属性（如果定义了），否则是 [`BoundField.auto_id`](/zh-hans/6.0/ref/forms/api/#django.forms.BoundField.auto_id)。

在循环单选按钮时，`label` 和 `input` 标签分别包含 `for` 和 `id` 属性。每个单选按钮都有一个 `id_for_label` 属性来输出元素的 ID。

#### `CheckboxSelectMultiple`

#### `class CheckboxSelectMultiple`

- `template_name`：`'django/forms/widgets/checkbox_select.html'`
- `option_template_name`：`'django/forms/widgets/checkbox_option.html'`

类似于 [`SelectMultiple`](#django.forms.SelectMultiple)，但渲染为一个复选框列表。

```html
<div>
  <div><input type="checkbox" name="..." ></div>
  ...
</div>
```

外部 `<div>` 容器接收部件的 `id` 属性（如果定义了），否则是 [`BoundField.auto_id`](/zh-hans/6.0/ref/forms/api/#django.forms.BoundField.auto_id)。

像 [`RadioSelect`](#django.forms.RadioSelect) 一样，你可以循环使用各个复选框来进行部件的选择。与 [`RadioSelect`](#django.forms.RadioSelect) 不同的是，如果字段是必填的，则复选框不会包含 `required` HTML 属性，因为浏览器验证会要求选中所有复选框，而不是至少一个。

在循环复选框时，`label` 和 `input` 标签分别包含 `for` 和 `id` 属性。每个复选框都有一个 `id_for_label` 属性来输出元素的 ID。

### 文件上传部件

#### `FileInput`

#### `class FileInput`

- `template_name`：`'django/forms/widgets/file.html'`
- 渲染为：`<input type="file" ...>`

#### `ClearableFileInput`

#### `class ClearableFileInput`

- `template_name`：`'django/forms/widgets/clearable_file_input.html'`
- 渲染为 `<input type="file" ...>`，如果该字段不需要且有初始数据，则增加一个复选框输入，以清除该字段的值。

### 复合部件

#### `MultipleHiddenInput`

#### `class MultipleHiddenInput`

- `template_name`：`'django/forms/widgets/multiple_hidden.html'`
- 渲染为：多个 `<input type="hidden" ...>` 标签

一个处理具有值列表的字段的多个隐藏部件。

#### `SplitDateTimeWidget`

#### `class SplitDateTimeWidget`

- `template_name`：`'django/forms/widgets/splitdatetime.html'`

围绕两个小组件的封装器（使用 [`MultiWidget`](#django.forms.MultiWidget)）： [`DateInput`](#django.forms.DateInput) 代表日期， [`TimeInput`](#django.forms.TimeInput) 代表时间。必须使用 [`SplitDateTimeField`](/zh-hans/6.0/ref/forms/fields/#django.forms.SplitDateTimeField) 而不是 [`DateTimeField`](/zh-hans/6.0/ref/forms/fields/#django.forms.DateTimeField)。

`SplitDateTimeWidget` 有几个可选参数：

#### `date_format`

类似于 [`DateInput.format`](#django.forms.DateInput.format)

#### `time_format`

类似于 [`TimeInput.format`](#django.forms.TimeInput.format)

#### `date_attrs`

#### `time_attrs`

类似于 [`Widget.attrs`](#django.forms.Widget.attrs)。一个包含 HTML 属性的字典，要分别在渲染的 [`DateInput`](#django.forms.DateInput) 和 [`TimeInput`](#django.forms.TimeInput) 部件上设置。如果没有设置这些属性，则使用 [`Widget.attrs`](#django.forms.Widget.attrs) 代替。

#### `SplitHiddenDateTimeWidget`

#### `class SplitHiddenDateTimeWidget`

- `template_name`：`'django/forms/widgets/splithiddendatetime.html'`

类似于 [`SplitDateTimeWidget`](#django.forms.SplitDateTimeWidget)，但对日期和时间使用 [`HiddenInput`](#django.forms.HiddenInput)。

#### `SelectDateWidget`

#### `class SelectDateWidget`

- `template_name`：`'django/forms/widgets/select_date.html'`

围绕三个 [`Select`](#django.forms.Select) 部件的封装器：月、日、年各一个。

需要几个可选的参数：

#### `years`

在“年份”选择框中使用的可选年份列表／年份组。默认值是包含当前年份和未来 9 年的列表。

#### `months`

在“月份”选择框中可选择使用的月份。

字典的键与月数相对应（1 开头索引），其值是显示的月份：

```
MONTHS = {
    1: _("jan"),
    2: _("feb"),
    3: _("mar"),
    4: _("apr"),
    5: _("may"),
    6: _("jun"),
    7: _("jul"),
    8: _("aug"),
    9: _("sep"),
    10: _("oct"),
    11: _("nov"),
    12: _("dec"),
}
```

#### `empty_label`

如果 [`DateField`](/zh-hans/6.0/ref/forms/fields/#django.forms.DateField) 不是必需的， [`SelectDateWidget`](#django.forms.SelectDateWidget) 将在列表顶部有一个空的选择（默认是 ``` --`` ```）。你可以通过 `empty_label` 属性来改变这个标签的文本。`empty_label` 可以是 `string`、`list` 或者 `tuple`。当使用字符串时，所有的选择框都会有一个带这个标签的空选择。如果 `empty_label` 是一个由 3 个字符串元素组成的 `list` 或 `tuple`，选择框将有自己的自定义标签。标签的顺序应该是 `('year_label', 'month_label', 'day_label')`。

```python
# A custom empty label with string
field1 = forms.DateField(widget=SelectDateWidget(empty_label="Nothing"))

# A custom empty label with tuple
field1 = forms.DateField(
    widget=SelectDateWidget(
        empty_label=("Choose Year", "Choose Month", "Choose Day"),
    ),
)
```
