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
將