django 1.8 官方文档翻译:5-1-4 内建的Widget

Widgets

Widget 是Django 对HTML 输入元素的表示。Widget 负责渲染HTML和提取GET/POST 字典中的数据。

小贴士

不要将Widget 与_表单字段_搞混淆。表单字段负责验证输入并直接在模板中使用。Widget 负责渲染网页上HTML 表单的输入元素和提取提交的原始数据。但是,Widget 需要_赋值_给表单的字段。

指定Widget

每当你指定表单的一个字段的时候,Django 将使用适合其数据类型的默认Widget。若要查找每个字段使用的Widget,参见_内建的字段_文档。

然而,如果你想要使用一个不同的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 都有可选的参数;它们可以在定义字段的Widget 时设置。在下面的示例中,设置了SelectDateWidgetyears 属性:

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_

继承自Select 的Widget

继承自Select 的Widget 负责处理HTML 选项。它们呈现给用户一个可以选择的选项列表。不同的Widget 以不同的方式呈现选项;Select 使用HTML 的列表形式<select>,而RadioSelect 使用单选按钮。

ChoiceField 字段默认使用Select。Widget 上显示的选项来自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 属性的Widget 也可以用于不是基于选项的字段 , 例如CharField —— 当选项与模型有关而不只是Widget 时,建议使用基于ChoiceField 的字段。

自定义Widget 的实例

当Django 渲染Widget 成HTML 时,它只渲染最少的标记 —— Django 不会添加class 的名称和特定于Widget 的其它属性。这表示,网页上所有TextInput 的外观是一样的。

有两种自定义Widget 的方式:基于每个_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 示例。

设置Widget 类的样式

可以添加(cssjavascript)给Widget,以及深度定制它们的外观和行为。

概况来讲,你需要子类化Widget 并_定义一个“Media” 内联类__创建一个“media” 属性_

这些方法涉及到Python 高级编程,详细细节在_表单Assets_ 主题中讲述。

Widget 的基类

WidgetMultiWidget 是所有_内建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:

如果你给一个属性赋值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" />'

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

    原文作者:飞龙
    原文地址: https://segmentfault.com/a/1190000003750554
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞