部件

部件

部件是 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 使用单选按钮。

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

这个表单将包含三个默认的 TextInput 小部件,使用默认的渲染方式 — 没有 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>

在一个真正的网页上,你可能不希望每个部件看起来都一样。你可能想要一个更大的评论输入元素,你可能想要 “姓名” 部件有一些特殊的 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)[源代码]

这个抽象类不能被渲染,但提供了基本属性 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。

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

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

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

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

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

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

  • render(name , value , attrs=None , renderer=None)[源代码]

使用给定的渲染器将部件渲染成 HTML。如果 renderer 为 None,则使用 FORM_RENDERER 设置中的渲染器。

给定一个数据字典和这个部件的名称,返回这个部件的值。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。

给定一个表单字段的 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">'

还有一个必要的方法:

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

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

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

一个例子是 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_)[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L912>)

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

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

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


下面是一个例子,它子类为 MultiWidget,用于在不同的选择框中显示日期和年、月、日。这个部件的目的是与 [DateField](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.DateField> "django.forms.DateField") 而不是 [MultiValueField](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.MultiValueField> "django.forms.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](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.DateField> "django.forms.DateField") 就会把这个方法传给一个字符串代替,所以需要进行解析。最后的 `return` 处理的是 `value` 是 `None` 的时候,也就是说我们的子部件没有任何默认值。

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

## 内置部件

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

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

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

#### `TextInput`

 _class_ `TextInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L336>)

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

#### `NumberInput`

 _class_ `NumberInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L341>)

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

请注意,并不是所有的浏览器都支持在 `number` 输入类型中输入本地化的数字。Django 本身就避免在 [localize](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.Field.localize> "django.forms.Field.localize") 属性设置为 `True` 的字段中使用它们。

#### `EmailInput`

 _class_ `EmailInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L346>)

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

#### `URLInput`

 _class_ `URLInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L351>)

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

#### `PasswordInput`

 _class_ `PasswordInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L356>)

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

需要一个可选的参数:

  * `render_value`

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

#### `HiddenInput`

 _class_ `HiddenInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L370>)

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

请注意,还有一个 MultipleHiddenInput 部件,封装了一组隐藏的输入元素。

#### `DateInput`

 _class_ `DateInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L558>)

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

采用与 TextInput 相同的参数,多一个可选参数:

  * `format`

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

如果未提供 `format` 参数,则默认格式是在 [DATE_INPUT_FORMATS](/read/django-5.1-zh/d165.md#std-setting-DATE_INPUT_FORMATS) 中找到的第一个格式,并遵循 [本地格式化](&lt;https://docs.djangoproject.com/zh-hans/5.1/topics/i18n/formatting>)。此小部件不支持 `%U`、`%W` 和 `%j` 格式。

#### `DateTimeInput`

 _class_ `DateTimeInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L563>)

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

采用与 TextInput 相同的参数,多一个可选参数:

  * `format`

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

如果未提供 `format` 参数,则默认格式是在 [DATETIME_INPUT_FORMATS](/read/django-5.1-zh/d165.md#std-setting-DATETIME_INPUT_FORMATS) 中找到的第一个格式,并遵循 [本地格式化](&lt;https://docs.djangoproject.com/zh-hans/5.1/topics/i18n/formatting>)。此小部件不支持 `%U`、`%W` 和 `%j` 格式。

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

#### `TimeInput`

 _class_ `TimeInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L568>)

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

采用与 TextInput 相同的参数,多一个可选参数:

  * `format`

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

如果没有提供 `format` 参数,默认的格式是 [TIME_INPUT_FORMATS](/read/django-5.1-zh/d165.md#std-setting-TIME_INPUT_FORMATS) 中找到的第一种格式,并且尊重 [本地格式化](&lt;https://docs.djangoproject.com/zh-hans/5.1/topics/i18n/formatting>)。

关于微秒的处理,请参见 DateTimeInput。

#### `Textarea`

 _class_ `Textarea`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L533>)

  * `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`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L578>)

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

需要一个可选的参数:

  * `check_test`

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

#### `Select`

 _class_ `Select`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L755>)

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

  * `choices`

当表单字段没有 `choices` 属性时,这个属性是可选的。如果有,当 [Field](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.Field> "django.forms.Field") 属性更新时,它将覆盖你在这里设置的任何属性。

#### `NullBooleanSelect`

 _class_ `NullBooleanSelect`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L793>)

  * `template_name`:`'django/forms/widgets/select.html'`
  * `option_template_name`:`'django/forms/widgets/select_option.html'`

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

#### `SelectMultiple`

 _class_ `SelectMultiple`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L835>)

  * `template_name`:`'django/forms/widgets/select.html'`
  * `option_template_name`:`'django/forms/widgets/select_option.html'`

类似于 Select,但允许多选:`<select multiple>...</select>`。

#### `RadioSelect`

 _class_ `RadioSelect`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L851>)

  * `template_name`:`'django/forms/widgets/radio.html'`
  * `option_template_name`:`'django/forms/widgets/radio_option.html'`

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

...

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

{{ myform.beatles.label }} {% for radio in myform.beatles %}
{{ radio }}
{% endfor %}

这将产生以下 HTML:

Radio buttons

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

{{ myform.beatles.label }} {% for radio in myform.beatles %} {% endfor %}

…将导致以下 HTML:

Radio buttons

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

外部 `<div>` 容器接收部件的 `id` 属性(如果定义了),否则是 [BoundField.auto_id](&lt;/read/django-5.1-zh/b0fee67fbca763bc.md#django.forms.BoundField.auto_id> "django.forms.BoundField.auto_id")。

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

#### `CheckboxSelectMultiple`

 _class_ `CheckboxSelectMultiple`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L868>)

  * `template_name`:`'django/forms/widgets/checkbox_select.html'`
  * `option_template_name`:`'django/forms/widgets/checkbox_option.html'`

类似于 SelectMultiple,但渲染为一个复选框列表。

...

外部 `<div>` 容器接收部件的 `id` 属性(如果定义了),否则是 [BoundField.auto_id](&lt;/read/django-5.1-zh/b0fee67fbca763bc.md#django.forms.BoundField.auto_id> "django.forms.BoundField.auto_id")。

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

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

### 文件上传部件

#### `FileInput`

 _class_ `FileInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L413>)

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

#### `ClearableFileInput`

 _class_ `ClearableFileInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L460>)

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

### 复合部件

#### `MultipleHiddenInput`

 _class_ `MultipleHiddenInput`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L375>)

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

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

#### `SplitDateTimeWidget`

 _class_ `SplitDateTimeWidget`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L992>)

  * `template_name`:`'django/forms/widgets/splitdatetime.html'`

围绕两个小组件的封装器(使用 MultiWidget): DateInput 代表日期, TimeInput 代表时间。必须使用 [SplitDateTimeField](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.SplitDateTimeField> "django.forms.SplitDateTimeField") 而不是 [DateTimeField](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.DateTimeField> "django.forms.DateTimeField")。

`SplitDateTimeWidget` 有几个可选参数:

  * `date_format`

类似于 DateInput.format

  * `time_format`

类似于 TimeInput.format

  * `date_attrs`

  * `time_attrs`

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

#### `SplitHiddenDateTimeWidget`

 _class_ `SplitHiddenDateTimeWidget`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L1027>)

  * `template_name`:`'django/forms/widgets/splithiddendatetime.html'`

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

#### `SelectDateWidget`

 _class_ `SelectDateWidget`[[源代码]](&lt;https://github.com/django/django/blob/stable/5.1.x/django/forms/widgets.py#L1047>)

  * `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](&lt;/read/django-5.1-zh/f2ebcdf57a52c6e4.md#django.forms.DateField> "django.forms.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"), ), ) ```