# Django 3.2.11.dev 文档

# 部件

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

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

小技巧

部件不应该与 表单字段 混淆。表单字段处理输入验证的逻辑，直接在模板中使用。小组件处理 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` 使用单选按钮。

`Select` 部件默认用于 `ChoiceField` 字段。部件上显示的选择是继承自 `ChoiceField`，改变 `ChoiceField.options` 将更新 `Select.options`。例如：

    >>> 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()

这个表单将包含三个默认的 `TextInput` 部件，具有默认的渲染——没有 CSS 类，没有额外的属性。这意味着为每个小组件提供的输入框将被完全渲染：

    >>> f = CommentForm(auto_id=False)
    >>> f.as_table()
    <tr><th>Name:</th><td><input type="text" name="name" required></td></tr>
    <tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
    <tr><th>Comment:</th><td><input type="text" name="comment" required></td></tr>

在真实的网页上，你可能不希望每个小组件看起来都一样。你可能希望评论的输入元素更大，你可能希望“名称”部件有一些特殊的 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)
    >>> f.as_table()
    <tr><th>Name:</th><td><input type="text" name="name" class="special" required></td></tr>
    <tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
    <tr><th>Comment:</th><td><input type="text" name="comment" size="40" required></td></tr>

你也可以使用 `attrs` 设置 HTML `id`。参见 `BoundField.id_for_label` 的例子。

### 样式化部件类

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

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

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

## 基础部件类

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

### `Widget`

class `Widget`(attrs=None)

  这个抽象类不能被渲染，但提供了基本属性 `attrs`。 你也可以在自定义部件上实现或重写 `render()` 方法。

  `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'`：:meth:`format_value' 返回的值。
    - `'attrs'`：拟在渲染的部件上设置的 HTML 属性。`attrs` 属性和 `attrs` 参数的组合。
    - `''template_name'`：`self.template_name` 的值。

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

  `id_for_label`(id_)

    返回该部件的 HTML ID 属性，供 `<label>`，给定字段的 ID 使用。如果 ID 不可用，则返回 `None`。

    这个钩子是必要的，因为一些部件有多个 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_required_attribute`(initial)

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

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

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

    Changed in Django 3.1:

    在旧版本中，当设置了 `initial` 时， `FileInput` 会返回 `True`。

### `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)` 对，键将被附加到部件的 `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]

    小技巧

    请注意 `MultiValueField` 有一个补充方法 `compress()`，其职责与之相反——将所有成员字段的清理值合并为一个。

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

  `get_context`(name, value, attrs)

    In addition to the `'widget'` key described in `Widget.get_context()`, `MultiWidget` adds a `widget['subwidgets']` key.

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

        {% 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" ...>`

#### `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` 中找到的第一种格式，并且尊重 本地格式化。

#### `DateTimeInput`

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

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

  `format`

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

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

  默认情况下，时间值的微秒部分总是设置为 `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`，但在 `<li>` 标签中呈现为单选按钮列表：

      <ul>
        <li><input type="radio" name="..."></li>
        ...
      </ul>

  为了对生成的标记进行更精细的控制，你可以在模板中循环使用单选按钮。假设一个表单 `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 }}`——它们将被输出到一个带有 `<li>` 标签的 `<ul>` 中，如上。

  外层的 `<ul>` 容器接收部件的 `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`，但渲染为一个复选框列表。

      <ul>
        <li><input type="checkbox" name="..." ></li>
        ...
      </ul>

  外层的 `<ul>` 容器接收部件的 `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"),
            ),
        )