Django Widgets(元件)

Django Widgets(部件)

Widgets(部件)

一个 widget 对应一个 HTML form 输入元素,有两个功能,一是用于 HTML 渲染,二是 从 GET/POST 字典抽出数据。
Field类表现* 校验逻辑* ,而部件表现* 显示逻辑* 。


一. 指定 widgets
在form里为 form field 指定 widget
from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)
这里的 comment 会变成 Textarea,而不是 CharField


二. widgets 参数设置
widgets 具有可选的参数,可以在给 form field 定义 widget 时设置,下面的例子参数 year 被设置成 SelectDateWidget
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)
这个例子里 DateField 的 widget 被设置为 SelectDateWidget,实现了HTML特殊的订制。


三. 继承Select widget
继承Select widget可以订制选择项,人性化为用户提供选项列表。不同的widget生成不同的HTML类别,例如,Select widget 生成 <select>,而RadioSelect 生成 radio button。

Select 部件默认用于ChoiceField ,其所显示的HTML正是继承自 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')]
forms.RadioSelect 正是继承自 Select




四. 订制部件
Django 会把部件渲染成 HTML,但是不会给html元素添加 class 等属性,所以 TextInput 部件会显示同样的 HTML。有两种办法可以订制部件,一是基于部件的实例对象订制(订制 field 属性);二是继承部件,定义内部类(订制 css 和 js 文件的链接)。


1. 基于部件对象的订制
     在 Form 类里,对 field 指定widget,并传递一个参数 attrs,这个参数的类型是一个字典。

例如,有一个 Form 类:
from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()
这个 Form 类会使用默认的 TextInput 部件,这个部件默认是没有额外的属性的。这意味着类生成的每个实例都是一样的。
>>> 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>
在实际应用中,可能想添加一个CSS class。所以,可以给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'}))
用 CommentForm 渲染的 HTML 如下:
>>> 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>

2. 继承部件,定义内部类
     第二种方法:继承部件类,或定义内部类 Media,或创建一个 media 属性。

(1)定义内部类 Media
from django import forms

class CalendarWidget(forms.TextInput):
    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js', 'actions.js')
这个部件会生成 link 和 script 代码
>>> w = CalendarWidget()
>>> print(w.media)
<link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://static.example.com/animations.js"></script>
<script type="text/javascript" src="http://static.example.com/actions.js"></script>
https://docs.djangoproject.com/en/1.6/topics/forms/media/#assets-as-a-static-definition 在1.6的doc中又详细说明


(2)创建一个 Media 属性
class CalendarWidget(forms.TextInput):
    def _media(self):
        return forms.Media(css={'all': ('pretty.css',)},
                           js=('animations.js', 'actions.js'))
    media = property(_media)
https://docs.djangoproject.com/en/1.6/topics/forms/media/#media-as-a-dynamic-property 在Django 文档中又详细说明



五,部件类基类

所有内置的部件类都是继承自 Widget 和MultiWidget ,可以继承它们实现自己的部件功能。
详细参考 https://docs.djangoproject.com/en/1.6/ref/forms/widgets/#base-widget-classes 



六、内置部件类

1. 处理 input 的部件
TextInput   
NumberInput
EmailInput
URLInput
PasswordInput
HiddenInput
DateInput
DateTimeInput
TimeInput
Textarea

2. Selector 和 checkbox 部件
CheckboxInput
Select
NullBooleanSelect
RadioSelect
CheckboxSelectMultiple

3. File upload 部件
FileInput
ClearableFileInput

4. 合成部件
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget



以上就是Django部件的全部内容。