Widget 是Django 对HTML 输入元素的表示。Widget 负责渲染HTML和提取GET/POST 字典中的数据。javascript
小贴士css
不要将Widget 与_表单字段_搞混淆。表单字段负责验证输入并直接在模板中使用。Widget 负责渲染网页上HTML 表单的输入元素和提取提交的原始数据。可是,Widget 须要_赋值_给表单的字段。java
每当你指定表单的一个字段的时候,Django 将使用适合其数据类型的默认Widget。若要查找每一个字段使用的Widget,参见_内建的字段_文档。django
然而,若是你想要使用一个不一样的Widget,你能够在定义字段时使用widget
参数。例如:编程
from django import forms class CommentForm(forms.Form): name = forms.CharField() url = forms.URLField() comment = forms.CharField(widget=forms.Textarea)
这将使用一个Textarea
Widget来设置表单的评论 ,而不是默认的TextInput
Widget。缓存
不少Widget 都有可选的参数;它们能够在定义字段的Widget 时设置。在下面的示例中,设置了SelectDateWidget
的years
属性:ui
from django import forms from django.forms.extras.widgets import SelectDateWidget BIRTH_YEAR_CHOICES = ('1980', '1981', '1982') FAVORITE_COLORS_CHOICES = (('blue', 'Blue'), ('green', 'Green'), ('black', 'Black')) class SimpleForm(forms.Form): birth_year = forms.DateField(widget=SelectDateWidget(years=BIRTH_YEAR_CHOICES)) favorite_colors = forms.MultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, choices=FAVORITE_COLORS_CHOICES)
可用的Widget 以及它们接收的参数,参见_内建的Widget_。url
继承自Select
的Widget 负责处理HTML 选项。它们呈现给用户一个能够选择的选项列表。不一样的Widget 以不一样的方式呈现选项;Select
使用HTML 的列表形式<select>
,而RadioSelect
使用单选按钮。code
ChoiceField
字段默认使用Select
。Widget 上显示的选项来自ChoiceField
,对ChoiceField.choices
的改变将更新Select.choices
。例如:orm
>>> 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
属性的Widget 也能够用于不是基于选项的字段 , 例如CharField
—— 当选项与模型有关而不仅是Widget 时,建议使用基于ChoiceField
的字段。
当Django 渲染Widget 成HTML 时,它只渲染最少的标记 —— Django 不会添加class 的名称和特定于Widget 的其它属性。这表示,网页上全部TextInput
的外观是同样的。
有两种自定义Widget 的方式:基于每一个_Widget 实例_和基于每一个_Widget 类_。
若是你想让某个Widget 实例与其它Widget 看上去不同,你须要在Widget 对象实例化并赋值给一个表单字段时指定额外的属性(以及可能须要在你的CSS 文件中添加一些规则)。
例以下面这个简单的表单:
from django import forms class CommentForm(forms.Form): name = forms.CharField() url = forms.URLField() comment = forms.CharField()
这个表单包含三个默认的TextInput
Widget,以默认的方式渲染 —— 没有CSS 类、没有额外的属性。这表示每一个Widget 的输入框将渲染得如出一辙:
>>> f = CommentForm(auto_id=False) >>> f.as_table() <tr><th>Name:</th><td><input type="text" name="name" /></td></tr> <tr><th>Url:</th><td><input type="url" name="url"/></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
在真正得网页中,你可能不想让每一个Widget 看上去都同样。你可能想要给comment 一个更大的输入元素,你可能想让‘name’ Widget 具备一些特殊的CSS 类。能够指定‘type’ 属性来利用新式的HTML5 输入类型。在建立Widget 时使用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"/></td></tr> <tr><th>Url:</th><td><input type="url" name="url"/></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
你还可使用attrs
设置HTML id
。参见BoundField.id_for_label
示例。
能够添加(css
和javascript
)给Widget,以及深度定制它们的外观和行为。
概况来说,你须要子类化Widget 并_定义一个“Media” 内联类_ 或 _建立一个“media” 属性_。
这些方法涉及到Python 高级编程,详细细节在_表单Assets_ 主题中讲述。
Widget
和MultiWidget
是全部_内建Widget_ 的基类,并可用于自定义Widget 的基类。
_class _Widget
(_attrs=None_)
这是个抽象类,它不能够渲染,可是提供基本的属性attrs
。你能够在自定义的Widget 中实现或覆盖render()
方法。
attrs
包含渲染后的Widget 将要设置的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" />'
Changed in Django 1.8:
若是你给一个属性赋值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" />'
render
(_name_, _value_, _attrs=None_)
返回Widget 的HTML,为一个Unicode 字符串。子类必须实现这个方法,不然将引起NotImplementedError
。
它不会确保给出的‘value’ 是一个合法的输入,所以子类的实现应该防卫式地编程。
value_from_datadict
(_data_, _files_, _name_)
根据一个字典和该Widget 的名称,返回该Widget 的值。files
may contain data coming from request.
FILES. 若是没有提供value,则返回None
。 在处理表单数据的过程当中,value_from_datadict
可能调用屡次,因此若是你自定义并添加额外的耗时处理时,你应该本身实现一些缓存机制。
_class _MultiWidget
(_widgets_, _attrs=None_)
由多个Widget 组合而成的Widget。MultiWidget
始终与MultiValueField
联合使用。
MultiWidget
具备一个必选参数:
widgets
一个包含须要的Widget 的可迭代对象。
以及一个必需的方法:
decompress
(_value_)
这个方法接受来自字段的一个“压缩”的值,并返回“解压”的值的一个列表。能够假设输入的值是合法的,但不必定是非空的。
子类必须实现 这个方法,并且由于值可能为空,实现必需要防卫这点。
“解压”的基本原理是须要“分离”组合的表单字段的值为每一个Widget 的值。
有个例子是,SplitDateTimeWidget
将