窗口小部件¶ T0>

小部件是Django对HTML输入元素的表示。 该小部件处理HTML的呈现以及从与该小部件对应的GET / POST字典中提取数据。

由内置小部件生成的HTML使用HTML5语法,目标为<!DOCTYPE html> 例如,它使用布尔属性,如checked,而不是checked='checked'的XHTML样式。

小费

不应该将小部件与form fields混淆。 表单字段处理输入验证的逻辑,并直接在模板中使用。 小部件处理在网页上呈现HTML表单输入元素以及提取原始提交的数据。 However, widgets do need to be assigned to form fields.

指定小部件

每当你在表单上指定一个字段时,Django将使用一个适合于要显示的数据类型的默认小部件。 要查找在哪个字段上使用哪个小部件,请参阅有关Built-in Field classes的文档。

但是,如果要为字段使用不同的小部件,则可以在字段定义上使用widget参数。 例如:

from django import forms

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

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

为小部件设置参数

许多小部件都有可选的额外参数;在字段上定义小部件时可以设置它们。 在以下示例中,为SelectDateWidget设置years属性:

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

Select小部件继承的小部件

Select小部件继承的小部件处理选择。 他们向用户提供可供选择的选项列表。 不同的小部件呈现出不同的选择。 Select小部件本身使用<select> HTML列表表示,而RadioSelect使用单选按钮。

Select widgets are used by default on ChoiceField fields. 在窗口小部件上显示的选项是从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')]

提供choices属性的小部件可以用于不基于选择的字段 - 比如CharField - 但是推荐使用ChoiceField

定制小部件实例

当Django将一个小部件呈现为HTML时,它只会呈现非常小的标记 - Django不会添加类名称或任何其他小部件特定的属性。 这意味着,例如,所有的TextInput小部件将在您的网页上显示相同。

有两种方法可以自定义窗口小部件:per widget instanceper widget class

样式小部件实例

如果你想让一个小部件实例与另一个小部件实例看起来不同,那么当小部件对象被实例化并分配给一个表单字段(也许在你的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'}))

然后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

造型小部件类

通过小部件,可以添加资源(cssjavascript),并更深入地定制其外观和行为。

In a nutshell, you will need to subclass the widget and either define a “Media” inner class or create a “media” property.

这些方法涉及到有些高级的Python编程,在Form Assets主题指南中详细介绍。

基础窗口小部件类

基础窗口小部件类WidgetMultiWidget由所有built-in widgets分类,可以作为自定义窗口小部件的基础。

Widget

Widget(attrs=None)[source]

这个抽象类不能被渲染,但是提供了基本的属性attrs 您也可以在自定义小部件上实现或覆盖render()方法。

ATTRS T0> ¶ T1>

包含要在呈现的小部件上设置的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" required />'

如果将TrueFalse赋值给某个属性,则该属性将呈现为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 T0> ¶ T1>

默认为True的属性。 如果设置为Falsedatetimetime的微秒部分将被设置为0

format_value(value)[source]

清理并返回一个在小部件模板中使用的值。 value isn’t guaranteed to be valid input, therefore subclass implementations should program defensively.

get_context(name, value, attrs)[source]
Django 1.11新增功能

返回渲染窗口小部件模板时使用的值的字典。 By default, the dictionary contains a single key, 'widget', which is a dictionary representation of the widget containing the following keys:

  • 'name'name参数中的字段名称。
  • 'is_hidden':指示这个小部件是否隐藏的布尔值。
  • 'required':指示是否需要此窗口小部件的字段的布尔值。
  • 'value':由format_value()返回的值。
  • 'attrs':要在呈现的小部件上设置的HTML属性。 attrs属性和attrs参数的组合。
  • 'template_name'self.template_name的值。

Widget subclasses can provide custom context values by overriding this method.

id_for_label(id_)[source]

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

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

render(name, value, attrs=None, renderer=None)[source]

使用给定的渲染器将小部件渲染为HTML。 如果rendererNone,则使用FORM_RENDERER设置中的呈现器。

在Django 1.11中更改:

添加了renderer参数。 支持不接受它的子类将在Django 2.1中被删除。

value_from_datadict数据文件名称[source] T6>

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

value_omitted_from_datadatafilesname[source] T6>

给定datafiles字典和此小部件的名称,返回小部件是否有数据或文件。

该方法的结果会影响模型表单falls back to its default

Special cases are CheckboxInput, CheckboxSelectMultiple, and SelectMultiple, which always return False because an unchecked checkbox and unselected <select multiple> don’t appear in the data of an HTML form submission, so it’s unknown whether or not the user submitted a value.

use_required_attribute(initial)[source]

给定表单字段的initial值,返回是否可以使用required HTML属性呈现小部件。 表单使用此方法以及Field.requiredForm.use_required_attribute来确定是否显示每个字段的required属性。

默认情况下,为隐藏的小部件返回False,否则返回True 特殊情况是ClearableFileInput,它在initial没有设置时返回False,并且CheckboxSelectMultiple,总是返回False,因为浏览器验证将要求所有复选框被选中而不是至少一个。

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

MultiWidget

MultiWidget(widgets, attrs=None)[source]

由多个小部件组成的小部件。 MultiWidget works hand in hand with the MultiValueField.

MultiWidget has one required argument:

小窗口 T0> ¶ T1>

包含所需小部件的迭代器。

而一个必要的方法:

decompress(value)[source]

此方法从字段中获取单个“压缩”值,并返回“解压缩”值的列表。 输入值可以被认为是有效的,但不一定是非空的。

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

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

An example of this is how SplitDateTimeWidget turns a datetime value into a list with date and time split into two separate values:

from django.forms import MultiWidget

class SplitDateTimeWidget(MultiWidget):

    # ...

    def decompress(self, value):
        if value:
            return [value.date(), value.time().replace(microsecond=0)]
        return [None, None]

小费

Note that MultiValueField has a complementary method compress() with the opposite responsibility - to combine cleaned values of all member fields into one.

它提供了一些定制上下文:

get_context(name, value, attrs)[source]

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

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

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

下面是一个示例窗口小部件,该窗口小部件使用MultiWidget在不同的选择框中显示日期,月份和年份。 这个小部件旨在与DateField而不是一个MultiValueField一起使用,因此我们实现了value_from_datadict()

from datetime import date
from django.forms import widgets

class DateSelectorWidget(widgets.MultiWidget):
    def __init__(self, attrs=None):
        # create choices for days, months, years
        # example below, the rest snipped for brevity.
        years = [(year, year) for year in (2011, 2012, 2013)]
        _widgets = (
            widgets.Select(attrs=attrs, choices=days),
            widgets.Select(attrs=attrs, choices=months),
            widgets.Select(attrs=attrs, choices=years),
        )
        super().__init__(_widgets, attrs)

    def decompress(self, value):
        if value:
            return [value.day, value.month, value.year]
        return [None, None, None]

    def value_from_datadict(self, data, files, name):
        datelist = [
            widget.value_from_datadict(data, files, name + '_%s' % i)
            for i, widget in enumerate(self.widgets)]
        try:
            D = date(
                day=int(datelist[0]),
                month=int(datelist[1]),
                year=int(datelist[2]),
            )
        except ValueError:
            return ''
        else:
            return str(D)

构造函数在元组中创建几个Select小部件。 super类使用这个元组来设置小部件。

所需的方法decompress()datetime.date值分解为每个小部件对应的日,月和年值。 注意该方法如何处理valueNone的情况。

value_from_datadict()的默认实现返回对应于每个Widget的值列表。 This is appropriate when using a MultiWidget with a MultiValueField, but since we want to use this widget with a DateField which takes a single value, we have overridden this method to combine the data of all the subwidgets into a datetime.date. 该方法从POST字典中提取数据并构造并验证日期。 如果有效,我们返回字符串,否则返回一个空字符串,它将导致form.is_valid返回False

内置小部件

Django提供了所有基本HTML小部件的表示,以及django.forms.widgets模块中一些常用的小部件组,包括the input of textvarious checkboxes and selectorsuploading fileshandling of multi-valued input

处理文本输入的小部件

这些小部件使用HTML元素inputtextarea

TextInput

TextInput[source]
  • input_type'text'
  • template_name'django/forms/widgets/text.html'
  • 呈现为:&lt; input type =“text” ...&gt;

NumberInput

NumberInput[source]
  • input_type'number'
  • template_name'django/forms/widgets/number.html'
  • 呈现为:&lt; input type =“number” ...&gt;

请注意,并非所有浏览器都支持在number输入类型中输入本地化数字。 Django本身避免将它们用于localize属性设置为True的字段。

EmailInput

EmailInput[source]
  • input_type'email'
  • template_name'django/forms/widgets/email.html'
  • 呈现为:&lt; input type =“email” ...&gt;

URLInput

URLInput[source]
  • input_type'url'
  • template_name'django/forms/widgets/url.html'
  • 呈现为:&lt; input type =“url” ...&gt;

PasswordInput

PasswordInput[source]
  • input_type'password'
  • template_name'django/forms/widgets/password.html'
  • 呈现为:&lt; input type =“password” ...&gt;

采取一个可选参数:

render_value T0> ¶ T1>

确定在验证错误后重新显示表单时,窗口小部件是否有填充值(默认为False)。

HiddenInput

HiddenInput[source]
  • input_type'hidden'
  • template_name'django/forms/widgets/hidden.html'
  • 呈现为:&lt; input type =“hidden” ...&gt;

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

DateInput

DateInput[source]
  • input_type'text'
  • template_name'django/forms/widgets/date.html'
  • 呈现为:&lt; input type =“text” ...&gt;

TextInput具有相同的参数,还有一个可选的参数:

格式 T0> ¶ T1>

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

如果没有提供format参数,默认格式是在DATE_INPUT_FORMATS中找到的第一种格式,并且尊重Format localization

DateTimeInput

DateTimeInput[source]
  • input_type'text'
  • template_name'django/forms/widgets/datetime.html'
  • 呈现为:&lt; input type =“text” ...&gt;

TextInput具有相同的参数,还有一个可选的参数:

格式 T0> ¶ T1>

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

如果没有提供format参数,那么默认格式是在DATETIME_INPUT_FORMATS中找到的第一种格式,并且尊重Format localization

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

TimeInput

TimeInput[source]
  • input_type'text'
  • template_name'django/forms/widgets/time.html'
  • 呈现为:&lt; input type =“text” ...&gt;

TextInput具有相同的参数,还有一个可选的参数:

格式 T0> ¶ T1>

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

如果没有提供format参数,默认格式是在TIME_INPUT_FORMATS中找到的第一种格式,并且关于Format localization

有关微秒的处理,请参见DateTimeInput

Textarea

Textarea[source]
  • template_name'django/forms/widgets/textarea.html'
  • 渲染为:<textarea>...</textarea>

选择器和复选框小部件

这些小部件使用HTML元素<select>&lt; input type =“checkbox”&gt; t2 >和&lt; input type =“radio”&gt;

Widgets that render multiple choices have an option_template_name attribute that specifies the template used to render each choice. For example, for the Select widget, select_option.html renders the <option> for a <select>.

CheckboxInput

CheckboxInput[source]
  • input_type'checkbox'
  • template_name'django/forms/widgets/checkbox.html'
  • 呈现为:&lt; input type =“checkbox” ...&gt;

采取一个可选参数:

check_test T0> ¶ T1>

如果复选框应该被选中,则返回True,然后返回CheckboxInput的值。

Select

Select[source]
  • template_name'django/forms/widgets/select.html'
  • option_template_name'django/forms/widgets/select_option.html'
  • Renders as: <select><option ...>...</select>
选择 T0> ¶ T1>

当表单字段没有choices属性时,此属性是可选的。 如果是这样,当Field中的属性更新时,它将覆盖您在此处设置的任何内容。

NullBooleanSelect

NullBooleanSelect[source]
  • template_name'django/forms/widgets/select.html'
  • option_template_name'django/forms/widgets/select_option.html'

选择“未知”,“是”和“否”选项

SelectMultiple

SelectMultiple[source]
  • template_name'django/forms/widgets/select.html'
  • option_template_name'django/forms/widgets/select_option.html'

类似于Select,但允许多个选择:&lt; select multiple =“multiple”&gt; ...&lt; / select&gt; t5 > T3>

RadioSelect

RadioSelect[source]
  • 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作为它的小部件:

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

这将生成以下HTML:

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

包括<label>标签。 为了获得更细化,您可以使用每个单选按钮的tagchoice_labelid_for_label属性。 例如,这个模板...

{% for radio in myform.beatles %}
    <label for="{{ radio.id_for_label }}">
        {{ radio.choice_label }}
        <span class="radio">{{ radio.tag }}</span>
    </label>
{% endfor %}

...将导致以下HTML:

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

If you decide not to loop over the radio buttons – e.g., if your template simply includes {{ myform.beatles }} – they’ll be output in a <ul> with <li> tags, as above.

如果已定义,外部的<ul>容器将接收小部件的id属性,否则接收BoundField.auto_id

When looping over the radio buttons, the label and input tags include for and id attributes, respectively. 每个单选按钮都有一个id_for_label属性来输出元素的ID。

CheckboxSelectMultiple

CheckboxSelectMultiple[source]
  • 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属性,因为浏览器验证需要检查所有复选框而不是至少一个。

When looping over the checkboxes, the label and input tags include for and id attributes, respectively. 每个复选框都有一个id_for_label属性来输出元素的ID。

文件上传小部件

FileInput

FileInput[source]
  • template_name'django/forms/widgets/file.html'
  • 呈现为:&lt; input type =“file” ...&gt;

ClearableFileInput

ClearableFileInput[source]
  • template_name'django/forms/widgets/clearable_file_input.html'
  • 呈现为:&lt; input type =“file” ...&gt;如果该字段不是必需的并且具有初始数据,则清除该字段的值。

复合小部件

MultipleHiddenInput

MultipleHiddenInput[source]
  • template_name'django/forms/widgets/multiple_hidden.html'
  • 呈现为:multiple &lt; input type =“hidden” ...&gt;标记

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

选择 T0> ¶ T1>

当表单字段没有choices属性时,此属性是可选的。 如果是这样,当Field中的属性更新时,它将覆盖您在此处设置的任何内容。

SplitDateTimeWidget

SplitDateTimeWidget[source]
  • template_name'django/forms/widgets/splitdatetime.html'

在两个小部件周围包装(使用MultiWidget):DateInput为日期,TimeInput为时间。 必须与SplitDateTimeField而不是DateTimeField一起使用。

SplitDateTimeWidget has several optional arguments:

DATE_FORMAT T0> ¶ T1>

类似于DateInput.format

TIME_FORMAT T0> ¶ T1>

类似于TimeInput.format

date_attrs T0> ¶ T1>
time_attrs T0> ¶ T1>
Django 2.0新增功能

类似于Widget.attrs 包含要在呈现的DateInputTimeInput小部件上分别设置的HTML属性的字典。 如果这些属性没有设置,则改为使用Widget.attrs

SplitHiddenDateTimeWidget

SplitHiddenDateTimeWidget[source]
  • template_name'django/forms/widgets/splithiddendatetime.html'

SplitDateTimeWidget类似,但在日期和时间都使用HiddenInput

SelectDateWidget

SelectDateWidget[source]
  • template_name'django/forms/widgets/select_date.html'

围绕三个包装Select小部件:一个月,一天和一年。

采取几个可选参数:

年 T0> ¶ T1>

在“年份”选择框中使用的可选列表/元组。 默认是包含当年和未来9年的清单。

个月 T0> ¶ T1>

在“个月”选择框中使用几个月的可选字典。

字典的键对应于月份编号(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 T0> ¶ T1>

If the DateField is not required, SelectDateWidget will have an empty choice at the top of the list (which is --- by default). 您可以使用empty_label属性更改此标签的文本。 empty_label可以是stringlisttuple 当使用一个字符串时,所有的选择框都会有一个空的标签。 如果empty_label是3个字符串元素的listtuple,则选择框将具有自己的自定义标签。 标签的顺序应该是('y​​ear_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"),
    ),
)