# Django 5.2.8 documentation

# 部件

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

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

Tip

部件不应该与 表单字段 混淆。表单字段处理输入验证的逻辑，直接在模板中使用。小组件处理 HTML 表单输入元素在网页上的渲染和原始提交数据的提取。然而，部件确实需要 分配 到表单字段。

## 指定部件

每当你在表单中指定一个字段时，Django 会使用一个默认的部件来显示数据类型。要想知道哪个字段使用的是哪个部件，请看 内置 Field 类 的文档。

但是，如果你想为一个字段使用不同的部件，你可以在字段定义中使用 `widget` 参数。例如：

    from django import forms

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

这将指定一个带有注释的表单，该表单使用一个较大的 `Textarea` 部件，而不是默认的 `TextInput` 部件。

## 为部件设置参数

许多部件都有可选的额外参数；它们可以在字段上定义部件时进行设置。在下面的例子中， `years` 属性被设置为 `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,
        )

请参阅 内置部件，了解更多关于哪些部件可用以及它们接受哪些参数的信息。

## 继承自 `Select` 部件的部件。

继承自 `Select` 部件的部件处理选择。它们向用户提供了一个可供选择的选项列表。不同的部件以不同的方式呈现这种选择；`Select` 部件本身使用 `<select>` HTML 列表表示，而 `RadioSelect` 使用单选按钮。

`ChoiceField` 字段默认使用 `Select` 小部件。小部件上显示的选项从 `ChoiceField` 继承，并且更改 `ChoiceField.choices` 将更新 `Select.choices`。例如：

    >>> from django import forms
    >>> CHOICES = {"1": "First", "2": "Second"}
    >>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
    >>> choice_field.choices
    [('1', 'First'), ('2', 'Second')]
    >>> choice_field.widget.choices
    [('1', 'First'), ('2', 'Second')]
    >>> choice_field.widget.choices = []
    >>> choice_field.choices = [("1", "First and only")]
    >>> choice_field.widget.choices
    [('1', 'First and only')]

然而，提供 `chips` 属性的部件可以与非基于选择的字段一起使用——例如 `CharField`——但当选择是模型固有的，而不仅仅是表示部件时，建议使用 `ChoiceField` 为基础的字段。

## 自定义部件实例

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

有两种方法来定制部件： 每个部件实例 和 每个部件类。

### 样式化部件实例

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

例如，采取以下表单：

    from django import forms

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

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

    >>> 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` 参数：

    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` 属性：

    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` 设置 HTML `id`。参见 `BoundField.id_for_label` 的例子。

### 样式化部件类

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

简而言之，你需要对部件进行子类化，并且 定义一个内部“Media”类 或者 创建一个"media"属性。

这些方法涉及到一些高级的 Python 编程，在 表单静态资源 主题指南中有详细描述。

## 基础部件类

基础部件类 `Widget` 和 `MultiWidget` 被所有的 内置部件 子类化，可以作为自定义部件的基础。

### `Widget`

class Widget(attrs=None)

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

  attrs

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

        >>> 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 的布尔属性：

        >>> 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` 和 `time` 值的微秒部分将被设置为 `0`。

  format_value(value)

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

  get_context(name, value, attrs)

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

    - `'name'`：`name` 参数中的字段名称。

    - `'is_hidden'`：表示该部件是否被隐藏的布尔值。

    - `'required'`：表示该部件是否需要该字段的布尔值。

    - `'value'`：`format_value()` 返回的值。

    - `'attrs'`：拟在渲染的部件上设置的 HTML 属性。`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` 设置中的渲染器。

  value_from_datadict(data, files, name)

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

  value_omitted_from_data(data, files, name)

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

    该方法的结果会影响模型表单中的字段 是否回到默认。

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

  use_fieldset

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

  use_required_attribute(initial)

    给定一个表单字段的 `initial` 值，返回是否可以用 `required` HTML 属性来渲染部件。表单使用这个方法与 `Field.required` 和 `Form.use_required_attribute` 一起决定是否为每个字段显示 `required` 属性。

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

    在与浏览器验证不兼容的自定义部件中覆盖此方法。例如，一个由隐藏的 `textarea` 元素支持的 WSYSIWG 文本编辑部件可能希望总是返回 `False` 以避免浏览器对隐藏字段的验证。

### `MultiWidget`

class MultiWidget(widgets, attrs=None)

  `MultiWidget` 与 `MultiValueField` 携手合作。

  `MultiWidget` 有一个必要的参数：

  widgets

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

        >>> 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` 中以生成属性值。你可以为一个小部件提供空字符串（`''`），以取消一个小部件的后缀。例如：

        >>> 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` 如何将一个 `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` 有一个补充方法 `compress()`，其职责与之相反——将所有成员字段的清理值合并为一个。

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

  get_context(name, value, attrs)

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

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

        {% for subwidget in widget.subwidgets %}
            {% include subwidget.template_name with widget=subwidget %}
        {% endfor %}

  下面是一个例子，它子类为 `MultiWidget`，用于在不同的选择框中显示日期和年、月、日。这个部件的目的是与 `DateField` 而不是 `MultiValueField` 一起使用，因此我们实现了 `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` 部件。`super()` 方法使用这个列表来建立部件。

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

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

## 内置部件

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

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

这些部件使用了 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` 属性设置为 `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` argument.

  Additionally, you can add server-side validation to your form field with a validator like `RegexValidator` or via third-party packages, such as 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` 部件，封装了一组隐藏的输入元素。

#### `DateInput`

class DateInput

  - `input_type`：`'text'`

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

  - 渲染为：`<input type="text" ...>`

  采用与 `TextInput` 相同的参数，多一个可选参数：

  format

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

  如果未提供 `format` 参数，则默认格式是在 `DATE_INPUT_FORMATS` 中找到的第一个格式，并遵循 本地格式化。此小部件不支持 `%U`、`%W` 和 `%j` 格式。

#### `DateTimeInput`

class DateTimeInput

  - `input_type`：`'text'`

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

  - 渲染为：`<input type="text" ...>`

  采用与 `TextInput` 相同的参数，多一个可选参数：

  format

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

  如果未提供 `format` 参数，则默认格式是在 `DATETIME_INPUT_FORMATS` 中找到的第一个格式，并遵循 本地格式化。此小部件不支持 `%U`、`%W` 和 `%j` 格式。

  默认情况下，时间值的微秒部分总是设置为 `0`。如果需要微秒，则使用 `supports_microseconds` 属性设置为 `True` 的子类。

#### `TimeInput`

class TimeInput

  - `input_type`：`'text'`

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

  - 渲染为：`<input type="text" ...>`

  采用与 `TextInput` 相同的参数，多一个可选参数：

  format

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

  如果没有提供 `format` 参数，默认的格式是 `TIME_INPUT_FORMATS` 中找到的第一种格式，并且尊重 本地格式化。

  关于微秒的处理，请参见 `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` 部件，`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` 属性更新时，它将覆盖你在这里设置的任何属性。

#### `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`，但允许多选：`<select multiple>...</select>`。

#### `RadioSelect`

class RadioSelect

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

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

  类似于 `Select`，但在 `<div>` 标签中呈现为一个单选按钮的列表：

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

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

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

  这将产生以下 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` 属性。例如，这个模板...

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

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

  在循环单选按钮时，`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`，但渲染为一个复选框列表。

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

  外部 `<div>` 容器接收部件的 `id` 属性（如果定义了），否则是 `BoundField.auto_id`。

像 `RadioSelect` 一样，你可以循环使用各个复选框来进行部件的选择。与 `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`）： `DateInput` 代表日期， `TimeInput` 代表时间。必须使用 `SplitDateTimeField` 而不是 `DateTimeField`。

  `SplitDateTimeWidget` 有几个可选参数：

  date_format

    类似于 `DateInput.format`

  time_format

    类似于 `TimeInput.format`

  date_attrs
  time_attrs

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

#### `SplitHiddenDateTimeWidget`

class SplitHiddenDateTimeWidget

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

  类似于 `SplitDateTimeWidget`，但对日期和时间使用 `HiddenInput`。

#### `SelectDateWidget`

class SelectDateWidget

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

  围绕三个 `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` 不是必需的， `SelectDateWidget` 将在列表顶部有一个空的选择（默认是 `--```）。你可以通过 `empty_label` 属性来改变这个标签的文本。`empty_label` 可以是 `string`、`list` 或者 `tuple`。当使用字符串时，所有的选择框都会有一个带这个标签的空选择。如果 `empty_label` 是一个由 3 个字符串元素组成的 `list` 或 `tuple`，选择框将有自己的自定义标签。标签的顺序应该是 `('year_label', 'month_label', 'day_label')`。

        # 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"),
            ),
        )