1. 程式人生 > >認識django2.0讀書筆記(7)---第七章 表單

認識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:

MAIL

/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)

  1. HTML裡我們定義了一個變數q。當提交表單時,變數q的值通過GET(method=”get”)附加在URL /search/上。注意q是在html中自定義的,並不是預設的或者沒有根據得來的。
  1. 處理/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應用程式(第十二章)。