認識django2.0讀書筆記(7)---第七章 表單
文件下載地址:Django_2.0_中文教程 http://download.csdn.net/detail/julius_lee/6620099
線上地址:http://djangobook.py3k.cn/2.0/
Django 2.0 Book 關鍵內容記錄,主要是為了幫助記憶和理清整個框架,同時以後忘了可以檢視,回想。
介紹django對使用者通過表單的提交進行的資料訪問,有效性檢查,及其處理
1、 request物件獲取資料
示例:view檢視函式
from django.http import HttpResponse def hello(request): return HttpResponse("Hello world")
HttpRequest物件包含當前請求URL的一些資訊:
屬性/方法 |
說明 |
舉例 |
request.path |
除域名以外的請求路徑,以正斜槓開頭 |
"/hello/" |
request.get_host() |
主機名(比如,通常所說的域名) |
"127.0.0.1:8000" or "www.example.com" |
request.get_full_path() |
請求路徑,可能包含查詢字串 |
"/hello/?print=true" |
request.is_secure() |
如果通過HTTPS訪問,則此方法返回True, 否則返回False |
True 或者 False2 |
在view函式裡,要始終用這個屬性或方法來得到URL,而不要手動輸入。 這會使得程式碼更加靈活,以便在其它地方重用。下面是一個簡單的例子:
# BAD!
def current_url_view_bad(request):
return HttpResponse("Welcome to the page at /current/")
# GOOD
def current_url_view_good(request):
return HttpResponse("Welcome to the page at %s" %request.path)
這樣,當收到請求後,直接轉為請求的路徑,以後修改都不用再改檢視函數了。
關於request.META
request.META是一個字典,包含http請求的Header資訊,內容如下:
程式碼:
def display_meta(request):
values = request.META.items()
values.sort()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>'% (k, v))
return HttpResponse('<table>%s</table>' % '\n'.join(html))
結果:
CONTENT_LENGTH |
|
CONTENT_TYPE |
text/plain |
CSRF_COOKIE |
vslS1e5VacqktmIG0ZnQMX5KJ1T7XxLV |
DJANGO_SETTINGS_MODULE |
mysite.settings |
GATEWAY_INTERFACE |
CGI/1.1 |
HOME |
/home/loongson |
HTTP_ACCEPT |
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
HTTP_ACCEPT_ENCODING |
gzip, deflate |
HTTP_ACCEPT_LANGUAGE |
zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 |
HTTP_CONNECTION |
keep-alive |
HTTP_COOKIE |
bdshare_firstime=1361237552004; csrftoken=vslS1e5VacqktmIG0ZnQMX5KJ1T7XxLV; sessionid=smdblfqnq9kio5syti5vmqgdo8pqek7r |
HTTP_DNT |
1 |
HTTP_HOST |
172.16.3.62:8080 |
HTTP_USER_AGENT |
Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0 |
LANG |
zh_CN.UTF-8 |
LANGUAGE |
zh_CN:zh |
LOGNAME |
loongson |
LS_COLORS |
rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36: |
|
/var/mail/loongson |
OLDPWD |
/home/loongson |
PATH |
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games |
PATH_INFO |
/values/ |
PWD |
/home/loongson/python/django/second_poll |
QUERY_STRING |
|
REMOTE_ADDR |
172.16.7.94 |
REMOTE_HOST |
|
REQUEST_METHOD |
GET |
RUN_MAIN |
true |
SCRIPT_NAME |
|
SERVER_NAME |
LOonux-3.local |
SERVER_PORT |
8080 |
SERVER_PROTOCOL |
HTTP/1.1 |
SERVER_SOFTWARE |
WSGIServer/0.1 Python/2.6.6 |
SHELL |
/bin/bash |
SHLVL |
1 |
SSH_CLIENT |
172.16.7.94 65295 22 |
SSH_CONNECTION |
172.16.7.94 65295 172.16.3.62 22 |
SSH_TTY |
/dev/pts/1 |
TERM |
xterm |
TZ |
Asia/Shanghai |
USER |
loongson |
XDG_RUNTIME_DIR |
/run/user/loongson |
XDG_SESSION_COOKIE |
51a0886c4aebc7a8473cc3a2000008c4-1385514067.991625-1414976123 |
XDG_SESSION_ID |
194c |
_ |
/usr/bin/python |
wsgi.errors |
|
wsgi.file_wrapper |
wsgiref.util.FileWrapper |
wsgi.input |
|
wsgi.multiprocess |
False |
wsgi.multithread |
True |
wsgi.run_once |
False |
wsgi.url_scheme |
http |
wsgi.version |
(1, 0) |
注意:
因為request.META 是一個普通的Python字典,因此當試圖訪問一個不存在的鍵時,會觸發一個KeyError異常。 (HTTP header資訊是由使用者的瀏覽器所提交的、不應該給予信任的“額外”資料,因此應該好好設計你的應用以便當一個特定的Header資料不存在時,給出一個優雅的迴應。)用 try/except 語句,或者用Python字典的 get() 方法來處理這些“可能不存在的鍵”:
示例:
# BAD!
def ua_display_bad(request):
ua = request.META['HTTP_USER_AGENT'] # Might raise KeyError!
return HttpResponse("Your browser is %s" % ua)
# GOOD (VERSION 1)
def ua_display_good1(request):
try:
ua = request.META['HTTP_USER_AGENT']
except KeyError:
ua = 'unknown'
return HttpResponse("Your browser is %s" % ua)
# GOOD (VERSION 2)
def ua_display_good2(request):
ua = request.META.get('HTTP_USER_AGENT', 'unknown')
return HttpResponse("Your browser is %s" % ua)
使用try或者get避免header資料不存在引發的異常。
2、 提交資料資訊
HttpRequest 還包含使用者提交的資訊:request.GET和request.POST,為類字典物件。
request.GET和request.POST都有get()、keys()和values()方法,你可以用用 for key in request.GET 獲取所有的鍵。
POST資料是來自HTML中的〈form〉標籤提交的,而GET資料可能來自〈form〉提交也可能是URL中的查詢字串(the query string)。
3、 表單處理示例
表單開發分為:前端HTML頁面介面,後臺view函式對提交資料處理過程
1) 建立搜尋表單
示例:books目錄下建立views.py
from django.shortcuts importrender_to_response
def search_form(request):
return render_to_response('search_form.html')
再在templates中建立search_form.html模板
<html>
<head>
<title>Search</title>
</head>
<body>
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
最後新增URLpattern到urls.py中
from mysite.books import views
urlpatterns = patterns('',
#...
(r'^search-form/$', views.search_form),
#...
)
這樣就可以出現一個搜尋框在頁面左上角了;也就是修改三個地方,view函式,url地址和html檔案。Html檔案需要了解其語法,才好書寫。
但提交資料會報錯404,因為form指向的search還沒有實現;
需要新增第二個檢視,並設定url如下:
# urls.py
urlpatterns = patterns('',
#...
(r'^search-form/$', views.search_form),#注意變數的寫法,檔名.函式名
(r'^search/$', views.search),
#...
)
# views.py
def search(request):
if 'q' in request.GET:
message = 'You searched for: %r' % request.GET['q']#q源於html文件的name定義
else:
message = 'You submitted an empty form.'
return HttpResponse(message)
- 在HTML裡我們定義了一個變數q。當提交表單時,變數q的值通過GET(method=”get”)附加在URL /search/上。注意q是在html中自定義的,並不是預設的或者沒有根據得來的。
- 處理/search/(search())的檢視通過request.GET來獲取q的值。
需要注意的是在這裡明確地判斷q是否包含在request.GET中。就像上面request.META小節裡面提到,對於使用者提交過來的資料,甚至是正確的資料,都需要進行過濾。 在這裡若沒有進行檢測,那麼使用者提交一個空的表單將引發KeyError異常
確認資料有效後,下一步將從資料庫查詢資料。
from django.http import HttpResponse
from django.shortcuts importrender_to_response
from mysite.books.models import Book
def search(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
books = Book.objects.filter(title__icontains=q)#使用icontains查詢,賦值給html中的books
return render_to_response('search_results.html',
{'books': books, 'query': q})#返回字典查詢結果,query是查詢的q 變數
else:
return HttpResponse('Please submit a search term.')
作用:
除了檢查q是否存在於request.GET之外,我們還檢查來reuqest.GET[‘q’]的值是否為空;
使用Book.objects.filter(title__icontains=q)獲取資料庫中標題包含q的書籍;
給模板傳遞來books,一個包含Book物件的列表;
查詢結果的顯示模板search_results.html如下:
<p>You Searched for :<strong>{{query }}</strong></p>
{% if books %}#books也就是q值,源於render_to_response
<p>Found {{ books|length }} book{{ books|pluralize }}.</p>#pluralize這個過濾器在適當的時候會輸出s(例如找到多本書籍)
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
{% else %}
<p>NO books matched your search criteria.</P>
{% endif %}
~
結果:
找到:
YouSearched for :Nono
Found 1 book.
Nono
沒有找到:
YouSearched for :Nono334
NO books matched your search criteria.
其介面如下圖所示:
4、 改進表單
首先,search()檢視對於空字串的處理相當薄弱——僅顯示一條”Please submit a search term.”的提示資訊。 若使用者要重新填寫表單必須自行點選“後退”按鈕, 這種做法既糟糕又不專業。
在檢測到空字串時更好的解決方法是重新顯示錶單,並在表單上面給出錯誤提示以便使用者立刻重新填寫。最簡單的實現方法既是新增else分句重新顯示錶單,程式碼如下:
from django.http import HttpResponse
from django.shortcuts importrender_to_response
from mysite.books.models import Book
def search_form(request):
return render_to_response('search_form.html')
def search(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
books = Book.objects.filter(title__icontains=q)
return render_to_response('search_results.html',
{'books': books, 'query': q})
else:
**return render_to_response('search_form.html', {'error': True})**#字串為空時重新顯示search_form.html
改進search()檢視:在字串為空時重新顯示search_form.html。 並且給這個模板傳遞了一個變數error,記錄錯誤提示資訊。 現在我們編輯一下search_form.html,檢測變數error,如下:
<html>
<head>
<title>Search</title>
</head>
<body>
**{% if error %}**#如果有錯,則顯示下列資訊
**<p style="color: red;">Please submit a searchterm.</p>**
**{% endif %}**
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
但是現在出現一個問題: 是否有必要專門編寫search_form()來顯示錶單? 按實際情況來說,當一個請求傳送至/search/(未包含GET的資料)後將會顯示一個空的表單(帶有錯誤資訊)。 所以,需要改變search()檢視:當用戶訪問/search/並未提交任何資料時就隱藏錯誤資訊,這樣就移去search_form()檢視以及 對應的URLpattern。
def search(request):
error = False
if 'q' in request.GET:
q = request.GET['q']
if not q:# 使用者提交了一個空表單,那麼它將看到錯誤提示資訊,還有表單
error = True
else:# 使用者提交了一個非空的值,那麼他將看到搜尋結果
books =Book.objects.filter(title__icontains=q)
return render_to_response('search_results.html',
{'books': books, 'query': q})
return render_to_response('search_form.html',
{'error': error})#使用者訪問/search/並且沒有帶有GET資料。則報錯
在改進後的檢視中,若使用者訪問/search/並且沒有帶有GET資料,那麼他將看到一個沒有錯誤資訊的表單; 如果使用者提交了一個空表單,那麼它將看到錯誤提示資訊,還有表單;最後,若使用者提交了一個非空的值,那麼他將看到搜尋結果。
既然已經將兩個檢視與URLs合併起來,/search/檢視管理著表單的顯示以及結果的顯示,那麼在search_form.html裡表單的action值就沒有必要硬編碼的指定URL。 原先的程式碼是這樣:
<form action="/search/"method="get">
現在改成這樣:
<form action=""method="get">
action=”“意味著表單將提交給與當前頁面相同的URL。
5、 簡單的驗證
主要是針對目前的資料驗證太過簡單,實際中會遇到特定格式的驗證,如郵件地址,郵編,日期等。
解決辦法:
Javascript驗證
伺服器端驗證
示例:
修改view函式
def search(request):
**errors = []**
if'q' in request.GET:
q = request.GET['q']
if not q:
**errors.append('Enter a search term.')**#利用append給出對應出錯提示
elif len(q) > 20: #限制字元長度
**errors.append('Please enter at most 20 characters.')**
else:
books = Book.objects.filter(title__icontains=q)
return render_to_response('search_results.html',
{'books': books, 'query': q})
return render_to_response('search_form.html',
{**'errors': errors** })
修改search_form.html檔案
<html>
<head>
<title>Search</title>
</head>
<body>
**{% if errors %}**
**<ul>**
**{% for error in errors %}**#顯示一個errors列表
**<li>{{ error }}</li>**
**{% endfor %}**
**</ul>**
**{% endif %}**
<form action="/search/" method="get">
<input type="text"name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
6、 編寫contact表單
示例:聯絡站點的表單
表單內容:使用者反饋資訊,email回信地址;表單提交驗證後,系統自動傳送email給站點人員
準備:新建一個contact資料夾在project下面,與books同級,建立空檔案__init__.py
1)編寫contact_form.html,定義主題,email和反饋資訊
<html>
<head>
<title>Contactus</title>
</head>
<body>
<h1>Contactus</h1>
{% if errors %}#如果有錯,則顯示錯誤資訊
<ul>
{% for error inerrors %}
<li>{{ error}}</li>
{% endfor %}
</ul>
{% endif %}
<formaction="/contact/" method="post">#method="post"會進行伺服器端操作,傳送email
<p>Subject:<input type="text" name="subject"></p>#標題
<p>Your e-mail(optional): <input type="text"name="email"></p>
<p>Message:<textarea name="message" rows="10"cols="50"></textarea></p>
<inputtype="submit" value="Submit">
</form>
</body>
</html>
2) 編寫contact檢視,
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts importrender_to_response
def contact(request):
errors = []
if request.method == 'POST':#<!--使用post,使用者瀏覽表單時不存在該值,只有提交表單後才有值-->
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '@' not in request.POST['email']:
errors.append('Enter a valid e-mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email','[email protected]'),
['[email protected]'],
)
return HttpResponseRedirect('/contact/thanks/')
return render_to_response('contact_form.html',
{'errors': errors})
說明:
使用request.POST代替request.GET來獲取提交過來的資料。 這是必須的,因為contact_form.html裡表單使用的是method=”post”。如果在視圖裡通過POST獲取資料,那麼request.GET將為空。
有兩個必填項,subject和 message,所以需要對這兩個進行驗證。注意,使用request.POST.get()方法,並提供一個空的字串作為預設值;這個方法很好的解決了鍵丟失與空資料問題。
雖然email非必填項,但如果有提交的值則也需進行驗證。驗證演算法相當的薄弱,僅驗證值是否包含@字元。 在實際應用中,需要更為健壯的驗證機制(Django提供這些驗證機制)。
使用了django.core.mail.send_mail函式來發送e-mail。 這個函式有四個必選引數: 主題,正文,寄信人和收件人列表。 send_mail是Django的EmailMessage類的一個方便的包裝,EmailMessage類提供了更高階的方法,比如附件,多部分郵 件,以及對於郵件頭部的完整控制。
當郵件傳送成功之後,使用HttpResponseRedirect物件將網頁重定向至一個包含成功資訊的頁面。但是要解釋一下為何重定向至新的頁面,而不是在模板中直接呼叫render_to_response()來輸出:原因就是: 若使用者重新整理一個包含POST表單的頁面,那麼請求將會重新發送造成重複。 這通常會造成非期望的結果,比如說重複的資料庫記錄;在例子中,將導致傳送兩封同樣的郵件。
應每次都給成功的POST請求做重定向。 這就是web開發的最佳實踐。
3) 表單的重新顯示
資料驗證失敗後返回表單中原來提交的資料,就不用再填寫一次正確的資料了。通過手動將原來提交的資料返回給模板,編輯html裡的各欄位填充原來的值
示例:
# views.py
def contact(request):
errors = []
if request.method == 'POST':
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '@' not in request.POST['email']:
errors.append('Enter a valid e-mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email',`'[email protected]`_'),
[`'[email protected]`_'],
)
return HttpResponseRedirect('/contact/thanks/')
return render_to_response('contact_form.html', { #增加了返回值
'errors': errors,
**'subject': request.POST.get('subject', ''),**
**'message': request.POST.get('message', ''),**
**'email': request.POST.get('email', ''),**
})
# contact_form.html
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if errors %}
<ul>
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<form action="/contact/"method="post"> <!--增加value值-->
<p>Subject: <input type="text" name="subject" **value="{{ subject}}"** ></p>
<p>Your e-mail (optional):<input type="text" name="email" **value="{{ email}}"** ></p>
<p>Message: <textarea name="message" rows="10" cols="50">**{{message }}**</textarea></p>
<input type="submit"value="Submit">
</form>
</body>
</html>
7、 第一個form類
Django.forms庫,處理html表單顯示及驗證
在存放views.py的目錄中建立form.py檔案
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()#使用charField型別
email = forms.EmailField(required=False)#emailFild型別,false表示email是可選項
message = forms.CharField()
實際上,這個類就是將對應的subject,email等內容格式化成為html內容,新增標籤等
示例:
>>> from contact.forms importContactForm
>>> f = ContactForm()
>>> print f
<tr><th><labelfor="id_subject">Subject:</label></th><td><inputtype="text" name="subject" id="id_subject"/></td></tr>
<tr><th><labelfor="id_email">Email:</label></th><td><inputtype="text" name="email" id="id_email"/></td></tr>
<tr><th><labelfor="id_message">Message:</label></th><td><inputtype="text" name="message" id="id_message"/></td></t
其次,進行資料的校驗
>>> f = ContactForm({'subject':'Hello', 'email': '[email protected]', 'message': 'Nice site!'})
>>> f.is_bound
True
例如以上建立了一個新的Form物件,並且傳入一個與定義匹配的字典型別資料,對一個Form實體賦值,得到了一個繫結form,呼叫任何繫結form的is_valid()方法,就可以知道它的資料是否合法
>>> f.is_valid()
True
1)檢視中使用form物件
示例:使用forms框架重寫contact
# views.py
from django.shortcuts importrender_to_response
from mysite.contact.forms importContactForm
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email','[email protected]'),
['[email protected]'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render_to_response('contact_form.html', {'form': form})
# contact_form.html
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
2)改變欄位顯示
在本地顯示這個表單的時,message欄位被顯示成`` input type=”text”`` ,而它應該被顯示成<`` textarea`` >。可以通過設定* widget* 來修改它:
from django import forms
class ContactForm(forms.Form):
subject= forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField(**widget=forms.Textarea** )# forms框架把每一個欄位的顯示邏輯分離到一組部件(widget)中
4) 設定最大長度
經常使用的校驗要求是檢查欄位長度。
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(**max_length=100** )#這樣顯示時使subject限制在100字元內
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
類似的還有min_length
5) 設定初始值
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email',`'[email protected]`_'),
[`'[email protected]`_'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm(
**initial={'subject': 'I love your site!'}**#為subject欄位新增初始值
)
return render_to_response('contact_form.html', {'form': form})
注意,傳入* 初始值* 資料和傳入資料以* 繫結* 表單是有區別的。 最大的區別是,如果僅傳入* 初始值* 資料,表單是unbound的,那意味著它沒有錯誤訊息。
6) 自定義校驗規則
示例:對提交的訊息規定必須大於4個字元,並建立自定義校驗欄位型別,希望`` message`` 欄位有一個額外的校驗,我們增加一個`` clean_message()`` 方法到`` Form`` 類:clean_message()方法將在指定欄位的預設校驗邏輯執行* 之後* 被呼叫。因為欄位資料已經被部分處理,所以它被從self.cleaned_data中提取出來了;
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
簡單地使用了len()和split()的組合來計算單詞的數量。 如果使用者輸入字數不足,我們丟擲一個forms.ValidationError型異常。這個異常的描述會被作為錯誤列表中的一項顯示給使用者。
在函式的末尾顯式地返回欄位
7) 指定標籤
需使用label,像這樣:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False, **label='Your e-mail address'**)#label自定義標籤
message = forms.CharField(widget=forms.Textarea)
8)定製form設計
在上面`` contact_form.html``模板中我們使用``{{form.as_table}}`` 顯示錶單,不過可以使用其他更精確控制表單顯示的方法,示例:
<style type="text/css">
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background-color: red;
color: white;
display: block;
font-size: 10px;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
修改form的顯示的最快捷的方式是使用CSS。自動生成的錯誤列表精確的使用`` <ulclass=”errorlist”>``
每一個欄位部件(<inputtype=”text”>, <select>, <textarea>, 或者類似)都可以通過訪問{{form.欄位名}}進行單獨的渲染。
示例:
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<div class="field">
{{ form.subject.errors }}
<label for="id_subject">Subject:</label>
{{ form.subject }}
</div>
<div class="field">
{{ form.email.errors }}
<label for="id_email">Your e-mail address:</label>
{{ form.email }}
</div>
<div class="field">
{{ form.message.errors }}
<label for="id_message">Message:</label>
{{ form.message }}
</div>
<input type="submit" value="Submit">
</form>
</body>
</html>
{{form.message.errors}} 會在 <ulclass="errorlist"> 裡面顯示,如果欄位是合法的,或者form沒有被繫結,就顯示一個空字串。
還可以把 form.message.errors當作一個布林值或者當它是list在上面做迭代, 例如:
<div class="field{% ifform.message.errors %} errors{% endif %}">
{% if form.message.errors %}
<ul>
{% for error in form.message.errors %}
<li><strong>{{ error }}</strong></li>
{% endfor %}
</ul>
{%endif %}
<label for="id_message">Message:</label>
{{ form.message }}
</div>
在校驗失敗的情況下, 這段程式碼會在包含錯誤欄位的div的class屬性中增加一個”errors”,在一個有序列表中顯示錯誤資訊。
這一章總結了本書的“核心教程”。
前七章介紹的內容就到此結束,後續再補充一些練習,鞏固後再繼續後續章節;
後面部分,從第八章到第十二章,將詳細講述高階(進階)使用,包括如何配置一個Django應用程式(第十二章)。