關(guān)于這頁(yè)文檔
這頁(yè)文檔簡(jiǎn)單介紹Web 表單的基本概念和它們?cè)贒jango 中是如何處理的。關(guān)于表單API 某方面的細(xì)節(jié),請(qǐng)參見(jiàn)表單 API、表單的字段和表單和字段的檢驗(yàn)。
除非你計(jì)劃構(gòu)建的網(wǎng)站和應(yīng)用只是發(fā)布內(nèi)容而不接受訪問(wèn)者的輸入,否則你將需要理解并使用表單。
Django 提供廣泛的工具和庫(kù)來(lái)幫助你構(gòu)建表單來(lái)接收網(wǎng)站訪問(wèn)者的輸入,然后處理以及響應(yīng)輸入。
在HTML中,表單是位于<form>...</form> 之間的元素的集合,它們?cè)试S訪問(wèn)者輸入文本、選擇選項(xiàng)、操作對(duì)象和控制等等,然后將信息發(fā)送回服務(wù)器。
某些表單的元素 —— 文本輸入和復(fù)選框 —— 非常簡(jiǎn)單而且內(nèi)建于HTML 本身。其它的表單會(huì)復(fù)雜些;例如彈出一個(gè)日期選擇對(duì)話框的界面、允許你移動(dòng)滾動(dòng)條的界面、使用JavaScript 和CSS 以及HTML 表單<input> 元素來(lái)實(shí)現(xiàn)操作控制的界面。
與<input> 元素一樣,一個(gè)表單必須指定兩樣?xùn)|西:
例如,Django Admin 站點(diǎn)的登錄表單包含幾個(gè)<input> 元素:type="text" 用于用戶名,type="password" 用于密碼,type="submit" 用于“Log in" 按鈕。它還包含一些用戶看不到的隱藏的文本字段,Django 使用它們來(lái)決定下一步的行為。
它還告訴瀏覽器表單數(shù)據(jù)應(yīng)該發(fā)往<form> 的action 屬性指定的URL —— /admin/,而且應(yīng)該使用method 屬性指定的HTTP 方法 —— post。
當(dāng)觸發(fā)<input type="submit" value="Log in"> 元素時(shí),數(shù)據(jù)將發(fā)送給/admin/。
處理表單時(shí)候只會(huì)用到GET和POST 方法。
Django 的登錄表單使用POST 方法,在這個(gè)方法中瀏覽器組合表單數(shù)據(jù)、對(duì)它們進(jìn)行編碼以用于傳輸、將它們發(fā)送到服務(wù)器然后接收它的響應(yīng)。
相反,GET 組合提交的數(shù)據(jù)為一個(gè)字符串,然后使用它來(lái)生成一個(gè)URL。這個(gè)URL 將包含數(shù)據(jù)發(fā)送的地址以及數(shù)據(jù)的鍵和值。如果你在Django 文檔中做一次搜索,你會(huì)立即看到這點(diǎn),此時(shí)將生成一個(gè)https://docs.djangoproject.com/search/?q=forms&release=1 形式的URL。
GET 和POST 用于不同的目的。
用于改變系統(tǒng)狀態(tài)的請(qǐng)求 —— 例如,給數(shù)據(jù)庫(kù)帶來(lái)變化的請(qǐng)求 —— 應(yīng)該使用POST。GET 只應(yīng)該用于不會(huì)影響系統(tǒng)狀態(tài)的請(qǐng)求。
GET 還不適合密碼表單,因?yàn)槊艽a將出現(xiàn)在URL 中,以及瀏覽器的歷史和服務(wù)器的日志中,而且都是以普通的文本格式。它還不適合數(shù)據(jù)量大的表單和二進(jìn)制數(shù)據(jù),例如一張圖片。使用GET 請(qǐng)求作為管理站點(diǎn)的表單具有安全隱患:攻擊者很容易模擬表單請(qǐng)求來(lái)取得系統(tǒng)的敏感數(shù)據(jù)。POST,如果與其它的保護(hù)措施結(jié)合將對(duì)訪問(wèn)提供更多的控制,例如Django 的CSRF 保護(hù)。
另一個(gè)方面,GET 適合網(wǎng)頁(yè)搜索這樣的表單,因?yàn)檫@種表示一個(gè)GET 請(qǐng)求的URL 可以很容易地作為書(shū)簽、分享和重新提交。
Django 在表單中的角色
處理表單是一件很復(fù)雜的事情??紤]一下Django 的Admin 站點(diǎn),不同類(lèi)型的大量數(shù)據(jù)項(xiàng)需要在一個(gè)表單中準(zhǔn)備好、渲染成HTML、使用一個(gè)方便的界面編輯、返回給服務(wù)器、驗(yàn)證并清除,然后保存或者向后繼續(xù)處理。
Django 的表單功能可以簡(jiǎn)化并自動(dòng)化大部分這些工作,而且還可以比大部分程序員自己所編寫(xiě)的代碼更安全。
Django 會(huì)處理表單工作中的三個(gè)顯著不同的部分:
可以手工編寫(xiě)代碼來(lái)實(shí)現(xiàn),但是Django 可以幫你完成所有這些工作。
我們已經(jīng)簡(jiǎn)短講述HTML 表單,但是HTML的<form> 只是其機(jī)制的一部分。
在一個(gè)Web 應(yīng)用中,‘表單’可能指HTML <form>、或者生成它的Django 的Form、或者提交時(shí)發(fā)送的結(jié)構(gòu)化數(shù)據(jù)、或者這些部分的總和。
表單系統(tǒng)的核心部分是Django 的Form 類(lèi)。Django 的模型描述一個(gè)對(duì)象的邏輯結(jié)構(gòu)、行為以及展現(xiàn)給我們的方式,與此類(lèi)似,Form 類(lèi)描述一個(gè)表單并決定它如何工作和展現(xiàn)。
模型類(lèi)的字典映射到數(shù)據(jù)庫(kù)的字典,與此類(lèi)似,表單類(lèi)的字段映射到HTML 的表單<input> 元素。(ModelForm通過(guò)一個(gè)Form 映射模型類(lèi)的字段到HTML 表單的<input>元素;Django 的Admin 站點(diǎn)就是基于這個(gè))。
表單的字段本身也是類(lèi);它們管理表單的數(shù)據(jù)并在表單提交時(shí)進(jìn)行驗(yàn)證。DateField 和FileField處理的數(shù)據(jù)類(lèi)型差別很大,必須完成不同的事情。
表單字段在瀏覽器中呈現(xiàn)給用戶的是一個(gè)HTML 的“widget” —— 用戶界面的一個(gè)片段。每個(gè)字段類(lèi)型都有一個(gè)合適的默認(rèn)Widget 類(lèi),需要時(shí)可以覆蓋。
在Django 中渲染一個(gè)對(duì)象時(shí),我們通常:
在模板中渲染表單和渲染其它類(lèi)型的對(duì)象幾乎一樣,除了幾個(gè)關(guān)鍵的差別。
在模型實(shí)例不包含數(shù)據(jù)的情況下,在模板中對(duì)它做處理很少有什么用處。但是渲染一個(gè)未填充的表單卻非常有意義 —— 我們希望用戶去填充它。
所以當(dāng)我們?cè)谝晥D中處理模型實(shí)例時(shí),我們一般從數(shù)據(jù)庫(kù)中獲取它。當(dāng)我們處理表單時(shí),我們一般在視圖中實(shí)例化它。
當(dāng)我們實(shí)例化表單時(shí),我們可以選擇讓它為空還是預(yù)先填充它,例如使用:
最后一種情況最令人關(guān)注,因?yàn)樗沟糜脩艨梢圆恢皇情喿x一個(gè)網(wǎng)站,而且可以給網(wǎng)站返回信息。
假設(shè)你想在你的網(wǎng)站上創(chuàng)建一個(gè)簡(jiǎn)單的表單,以獲得用戶的名字。你需要類(lèi)似這樣的模板:
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>
這告訴瀏覽器發(fā)送表單的數(shù)據(jù)到URL /your-name/,并使用POST 方法。它將顯示一個(gè)標(biāo)簽為"Your name:"的文本字段,和一個(gè)"OK"按鈕。如果模板上下文包含一個(gè)current_name 變量,它將用于預(yù)填充your_name 字段。
你將需要一個(gè)視圖來(lái)渲染這個(gè)包含HTML 表單的模板,并提供合適的current_name 字段。
當(dāng)表單提交時(shí),發(fā)往服務(wù)器的POST 請(qǐng)求將包含表單數(shù)據(jù)。
現(xiàn)在你還需要一個(gè)對(duì)應(yīng)/your-name/ URL 的視圖,它在請(qǐng)求中找到正確的鍵/值對(duì),然后處理它們。
這是一個(gè)非常簡(jiǎn)單的表單。實(shí)際應(yīng)用中,一個(gè)表單可能包含幾十上百個(gè)字段,其中大部分需要預(yù)填充,而且我們預(yù)料到用戶將來(lái)回編輯-提交幾次才能完成操作。
我們可能需要在表單提交之前,在瀏覽器端作一些驗(yàn)證。我們可能想使用非常復(fù)雜的字段,以允許用戶做類(lèi)似從日歷中挑選日期這樣的事情,等等。
這個(gè)時(shí)候,讓Django 來(lái)為我們完成大部分工作是很容易的。
我們已經(jīng)計(jì)劃好了我們的 HTML 表單應(yīng)該呈現(xiàn)的樣子。在Django 中,我們的起始點(diǎn)是這里:
#forms.py
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
它定義一個(gè)Form 類(lèi),只帶有一個(gè)字段(your_name)。我們已經(jīng)對(duì)這個(gè)字段使用一個(gè)友好的標(biāo)簽,當(dāng)渲染時(shí)它將出現(xiàn)在<label> 中(在這個(gè)例子中,即使我們省略它,我們指定的label還是會(huì)自動(dòng)生成)。
字段允許的最大長(zhǎng)度通過(guò)max_length 定義。它完成兩件事情。首先,它在HTML 的<input> 上放置一個(gè)maxlength="100" (這樣瀏覽器將在第一時(shí)間阻止用戶輸入多于這個(gè)數(shù)目的字符)。它還意味著當(dāng)Django 收到瀏覽器發(fā)送過(guò)來(lái)的表單時(shí),它將驗(yàn)證數(shù)據(jù)的長(zhǎng)度。
Form 的實(shí)例具有一個(gè)is_valid() 方法,它為所有的字段運(yùn)行驗(yàn)證的程序。當(dāng)調(diào)用這個(gè)方法時(shí),如果所有的字段都包含合法的數(shù)據(jù),它將:
Truecleaned_data屬性中。完整的表單,第一次渲染時(shí),看上去將像:
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100">
注意它不包含 <form> 標(biāo)簽和提交按鈕。我們必須自己在模板中提供它們。
發(fā)送給Django 網(wǎng)站的表單數(shù)據(jù)通過(guò)一個(gè)視圖處理,一般和發(fā)布這個(gè)表單的是同一個(gè)視圖。這允許我們重用一些相同的邏輯。
當(dāng)處理表單時(shí),我們需要在視圖中實(shí)例化它:
#views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
如果訪問(wèn)視圖的是一個(gè)GET 請(qǐng)求,它將創(chuàng)建一個(gè)空的表單實(shí)例并將它放置到要渲染的模板的上下文中。這是我們?cè)诘谝粋€(gè)訪問(wèn)該URL 時(shí)預(yù)期發(fā)生的情況。
如果表單的提交使用POST 請(qǐng)求,那么視圖將再次創(chuàng)建一個(gè)表單實(shí)例并使用請(qǐng)求中的數(shù)據(jù)填充它:form = NameForm(request.POST)。這叫做”綁定數(shù)據(jù)至表單“(它現(xiàn)在是一個(gè)綁定的表單)。
我們調(diào)用表單的is_valid()方法;如果它不為True,我們將帶著這個(gè)表單返回到模板。這時(shí)表單不再為空(未綁定),所以HTML 表單將用之前提交的數(shù)據(jù)填充,然后可以根據(jù)要求編輯并改正它。
如果is_valid()為True,我們將能夠在cleaned_data 屬性中找到所有合法的表單數(shù)據(jù)。在發(fā)送HTTP 重定向給瀏覽器告訴它下一步的去向之前,我們可以用這個(gè)數(shù)據(jù)來(lái)更新數(shù)據(jù)庫(kù)或者做其它處理。
我們不需要在name.html 模板中做很多工作。最簡(jiǎn)單的例子是:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
根據(jù){{ form }},所有的表單字段和它們的屬性將通過(guò)Django 的模板語(yǔ)言拆分成HTML 標(biāo)記 。
表單和跨站請(qǐng)求偽造的防護(hù)
Django 原生支持一個(gè)簡(jiǎn)單易用的跨站請(qǐng)求偽造的防護(hù)。當(dāng)提交一個(gè)啟用CSRF 防護(hù)的
POST表單時(shí),你必須使用上面例子中的csrf_token模板標(biāo)簽。然而,因?yàn)镃SRF 防護(hù)在模板中不是與表單直接捆綁在一起的,這個(gè)標(biāo)簽在這篇文檔的以下示例中將省略。HTML5 輸入類(lèi)型和瀏覽器驗(yàn)證
如果你的表單包含
URLField、EmailField和其它整數(shù)字段類(lèi)似,Django 將使用url、number這樣的HTML5 輸入類(lèi)型。默認(rèn)情況下,瀏覽器可能會(huì)對(duì)這些字段進(jìn)行它們自身的驗(yàn)證,這些驗(yàn)證可能比Django 的驗(yàn)證更嚴(yán)格。如果你想禁用這個(gè)行為,請(qǐng)?jiān)O(shè)置form標(biāo)簽的novalidate屬性,或者指定一個(gè)不同的字段,如TextInput。
現(xiàn)在我們有了一個(gè)可以工作的網(wǎng)頁(yè)表單,它通過(guò)Django Form 描述、通過(guò)視圖處理并渲染成一個(gè)HTML <form>。
這是你入門(mén)所需要知道的所有內(nèi)容,但是表單框架為了提供了更多的內(nèi)容。一旦你理解了上面描述的基本處理過(guò)程,你應(yīng)該可以理解表單系統(tǒng)的其它功能并準(zhǔn)備好學(xué)習(xí)更多的底層機(jī)制。
所有的表單類(lèi)都作為django.forms.Form 的子類(lèi)創(chuàng)建,包括你在Django 管理站點(diǎn)中遇到的ModelForm。
模型和表單
實(shí)際上,如果你的表單打算直接用來(lái)添加和編輯Django 的模型,ModelForm 可以節(jié)省你的許多時(shí)間、精力和代碼,因?yàn)樗鼘⒏鶕?jù)
Model類(lèi)構(gòu)建一個(gè)表單以及適當(dāng)?shù)淖侄魏蛯傩浴?/p>
綁定的和未綁定的表單 之間的區(qū)別非常重要:
表單的is_bound 屬性將告訴你一個(gè)表單是否具有綁定的數(shù)據(jù)。
考慮一個(gè)比上面的迷你示例更有用的一個(gè)表單,我們可以用它來(lái)在一個(gè)個(gè)人網(wǎng)站上實(shí)現(xiàn)“聯(lián)系我”功能:
#forms.py
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
我們前面的表單只使用一個(gè)字段your_name,它是一個(gè)CharField。在這個(gè)例子中,我們的表單具有四個(gè)字段:subject、message、sender 和cc_myself。共用到三種字段類(lèi)型:CharField、EmailField 和 BooleanField;完整的字段類(lèi)型列表可以在表單字段中找到。
每個(gè)表單字段都有一個(gè)對(duì)應(yīng)的Widget 類(lèi),它對(duì)應(yīng)一個(gè)HTML 表單Widget,例如<input type="text">。
在大部分情況下,字段都具有一個(gè)合理的默認(rèn)Widget。例如,默認(rèn)情況下,CharField 具有一個(gè)TextInput Widget,它在HTML 中生成一個(gè)<input type="text">。如果你需要<textarea>,在定義表單字段時(shí)你應(yīng)該指定一個(gè)合適的Widget,例如我們定義的message 字段。
不管表單提交的是什么數(shù)據(jù),一旦通過(guò)調(diào)用is_valid() 成功驗(yàn)證(is_valid() 返回True),驗(yàn)證后的表單數(shù)據(jù)將位于form.cleaned_data 字典中。這些數(shù)據(jù)已經(jīng)為你轉(zhuǎn)換好為Python 的類(lèi)型。
注
此時(shí),你依然可以從
request.POST中直接訪問(wèn)到未驗(yàn)證的數(shù)據(jù),但是訪問(wèn)驗(yàn)證后的數(shù)據(jù)更好一些。
在上面的聯(lián)系表單示例中,cc_myself 將是一個(gè)布爾值。類(lèi)似地,IntegerField 和FloatField 字段分別將值轉(zhuǎn)換為Python 的int 和float。
下面是在視圖中如何處理表單數(shù)據(jù):
#views.py
from django.core.mail import send_mail
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
提示
關(guān)于Django 中如何發(fā)送郵件的更多信息,請(qǐng)參見(jiàn)發(fā)送郵件。
有些字段類(lèi)型需要一些額外的處理。例如,使用表單上傳的文件需要不同地處理(它們可以從request.FILES 獲取,而不是request.POST)。如何使用表單處理文件上傳的更多細(xì)節(jié),請(qǐng)參見(jiàn)綁定上傳的文件到一個(gè)表單。
你需要做的就是將表單實(shí)例放進(jìn)模板的上下文。如果你的表單在Context 中叫做form,那么{{ form }}將正確地渲染它的<label> 和 <input>元素。
表單模板的額外標(biāo)簽
不要忘記,表單的輸出不 包含
<form>標(biāo)簽,和表單的submit按鈕。你必須自己提供它們。
對(duì)于<label>/<input> 對(duì),還有幾個(gè)輸出選項(xiàng):
{{ form.as_table }} 以表格的形式將它們渲染在<tr> 標(biāo)簽中{{ form.as_p }} 將它們渲染在<p> 標(biāo)簽中{{ form.as_ul }} 將它們渲染在<li> 標(biāo)簽中注意,你必須自己提供<table> 或<ul> 元素。
下面是我們的ContactForm 實(shí)例的輸出{{ form.as_p }}:
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
<input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
注意,每個(gè)表單字段具有一個(gè)ID屬性并設(shè)置為id_<field-name>,它被一起的label 標(biāo)簽引用。它對(duì)于確保屏幕閱讀軟件這類(lèi)的輔助計(jì)算非常重要。你還可以自定義label 和 id 生成的方式。
更多信息參見(jiàn) 輸出表單為HTML。
我們沒(méi)有必要非要讓Django 來(lái)分拆表單的字段;如果我們喜歡,我們可以手工來(lái)做(例如,這樣允許重新對(duì)字段排序)。每個(gè)字段都是表單的一個(gè)屬性,可以使用{{ form.name_of_field }} 訪問(wèn),并將在Django 模板中正確地渲染。例如:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
完整的<label> 元素還可以使用label_tag() 生成。例如:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
當(dāng)然,這個(gè)便利性的代價(jià)是更多的工作。直到現(xiàn)在,我們沒(méi)有擔(dān)心如何展示錯(cuò)誤信息,因?yàn)镈jango 已經(jīng)幫我們處理好。在下面的例子中,我們將自己處理每個(gè)字段的錯(cuò)誤和表單整體的各種錯(cuò)誤。注意,表單和模板頂部的{{ form.non_field_errors }} 查找每個(gè)字段的錯(cuò)誤。
使用{{ form.name_of_field.errors }} 顯示表單錯(cuò)誤的一個(gè)清單,并渲染成一個(gè)ul??瓷先タ赡芟瘢?/p>
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
這個(gè)ul 有一個(gè)errorlist CSS 類(lèi)型,你可以用它來(lái)定義外觀。如果你希望進(jìn)一步自定義錯(cuò)誤信息的顯示,你可以迭代它們來(lái)實(shí)現(xiàn):
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
空字段錯(cuò)誤(以及使用form.as_p() 時(shí)渲染的隱藏字段錯(cuò)誤)將渲染成一個(gè)額外的CSS 類(lèi)型nonfield 以幫助區(qū)分每個(gè)字段的錯(cuò)誤信息。例如,{{ form.non_field_errors }} 看上去會(huì)像:
<ul class="errorlist nonfield">
<li>Generic validation error</li>
</ul>
Changed in Django 1.8:
添加上面示例中提到的nonfield CSS 類(lèi)型。
參見(jiàn)Forms API 以獲得關(guān)于錯(cuò)誤、樣式以及在模板中使用表單屬性的更多內(nèi)容。
如果你為你的表單使用相同的HTML,你可以使用{% for %} 循環(huán)迭代每個(gè)字段來(lái)減少重復(fù)的代碼:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
{{ field }} 中有用的屬性包括:
{{ field.label }}
字段的label,例如Email address。
{{ field.label_tag }}
包含在HTML <label> 標(biāo)簽中的字段Label。它包含表單的label_suffix。例如,默認(rèn)的label_suffix 是一個(gè)冒號(hào):
<label for="id_email">Email address:</label>
{{ field.id_for_label }}
用于這個(gè)字段的ID(在上面的例子中是id_email)。如果你正在手工構(gòu)造label,你可能想使用它代替label_tag。如果你有一些內(nèi)嵌的JavaScript 并且想避免硬編碼字段的ID,這也是有用的。
{{ field.value }}
字段的值,例如someone@example.com。
{{ field.html_name }}
輸入元素的name 屬性中將使用的名稱。它將考慮到表單的前綴。
{{ field.help_text }}
與該字段關(guān)聯(lián)的幫助文檔。
{{ field.errors }}
輸出一個(gè)<ul class="errorlist">,包含這個(gè)字段的驗(yàn)證錯(cuò)誤信息。你可以使用{% for error in field.errors %}自定義錯(cuò)誤的顯示。 這種情況下,循環(huán)中的每個(gè)對(duì)象只是一個(gè)包含錯(cuò)誤信息的簡(jiǎn)單字符串。
{{ field.is_hidden }}
如果字段是隱藏字段,則為True,否則為False。作為模板變量,它不是很有用處,但是可以用于條件測(cè)試,例如:
{% if field.is_hidden %}
{% endif %}
{{ field.field }}
表單類(lèi)中的Field 實(shí)例,通過(guò)BoundField 封裝。你可以使用它來(lái)訪問(wèn)Field 屬性,例如{% char_field.field.max_length %}。
如果你正在手工布局模板中的一個(gè)表單,而不是依賴Django 默認(rèn)的表單布局,你可能希望將<input type="hidden"> 字段與非隱藏的字段區(qū)別對(duì)待。例如,因?yàn)殡[藏的字段不會(huì)顯示,在該字段旁邊放置錯(cuò)誤信息可能讓你的用戶感到困惑 —— 所以這些字段的錯(cuò)誤應(yīng)該有區(qū)別地來(lái)處理。
Django 提供兩個(gè)表單方法,它們?cè)试S你獨(dú)立地在隱藏的和可見(jiàn)的字段上迭代:hidden_fields() 和visible_fields()。下面是使用這兩個(gè)方法對(duì)前面一個(gè)例子的修改:
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
這個(gè)示例沒(méi)有處理隱藏字段中的任何錯(cuò)誤信息。通常,隱藏字段中的錯(cuò)誤意味著表單被篡改,因?yàn)檎5谋韱翁顚?xiě)不會(huì)改變它們。然而,你也可以很容易地為這些表單錯(cuò)誤插入一些錯(cuò)誤信息顯示出來(lái)。
如果你的網(wǎng)站在多個(gè)地方對(duì)表單使用相同的渲染邏輯,你可以保存表單的循環(huán)到一個(gè)單獨(dú)的模板中來(lái)減少重復(fù),然后在其它模板中使用include 標(biāo)簽來(lái)重用它:
# In your form template:
{% include "form_snippet.html" %}
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
如果傳遞到模板上下文中的表單對(duì)象具有一個(gè)不同的名稱,你可以使用include 標(biāo)簽的with 參數(shù)來(lái)對(duì)它起個(gè)別名:
{% include "form_snippet.html" with form=comment_form %}
如果你發(fā)現(xiàn)自己經(jīng)常這樣做,你可能需要考慮一下創(chuàng)建一個(gè)自定義的inclusion標(biāo)簽。
這里只是基礎(chǔ),表單還可以完成更多的工作:
另見(jiàn)
表單參考 覆蓋完整的API 參考,包括表單字段、表單Widget 以及表單和字段的驗(yàn)證。
譯者:Django 文檔協(xié)作翻譯小組,原文:Overview。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。