django表單


表單是交互性網站的支柱。

本文內容包括django對表單提交數據的訪問,有效性檢查以及其他處理,還有HttpRequest對象和Form對象。

一、HttpRequest的URL相關信息

定義views.py

def current_url_view(request):
    return HttpResponse("Welcome to the page at %s,host is %s,full path is %s,is_secure is %s" % (request.path,request.get_host(),request.get_full_path(),request.is_secure()))

可以顯示出:

Welcome to the page at /url/,host is 10.1.101.227:9000,full path is /url/,is_secure is False

二、request.META

顯示所有META,在views.py里增加函數display_meta。

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

三、request.GET和request.POST

POST數據是來自form表單提交的,GET數據可能來自form表單也可能來自url。

當提交表單僅僅需要獲取數據就使用GET,當提交表單需要更改服務器數據的狀態或者發e-mail,或者其他不僅僅是獲取顯示數據的情況就使用POST。

判斷request.method的值能很好的幫助我們將表單顯示[GET]表單處理[POST]隔離開來。

四、GET表單處理的例子

還是以書籍、作者、出版商為例。

表單的開發分為兩個部分:前端HTML頁面用戶接口和后台view函數對所提交數據的處理過程。

1、通過一個特別簡單的例子確認用戶提交的數據是有效的

首先建立前端html頁面接口,即通過建立一個view來顯示一個搜索表單,涉及三個文件:

urls.py

from books.views import *

urlpatterns = patterns('',
    # ...
    (r'^search-form/$', search_form),
    # ...
)
View Code

views.py

liuxiaoyan@development:~/mysite/books$ cat views.py
# Create your views here.
from django.shortcuts import render_to_response

def search_form(request):
    return render_to_response('search_form.html')
View Code

search_form.html模板

liuxiaoyan@development:~/mysite$ cat 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>
View Code

現在訪問/search-form/,可以看到一個簡單的搜索界面。你真正通過該form表單提交數據查找時會404,因為form指向的URL/search/還沒有實現。現在實現。

添加第二個視圖函數並設置URL。

urls.py

liuxiaoyan@development:~/mysite$ cat urls.py
from django.conf.urls.defaults import patterns, include, url 

from views import *
from books.views import *

urlpatterns = patterns('',
    (r'^search-form/$',search_form),
    (r'^search/$',search),
)
View Code

 views.py

liuxiaoyan@development:~/mysite/books$ cat views.py
# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponse   

def search_form(request):
    return render_to_response('search_form.html')
def search(request):
    if 'q' in request.GET:
        message='You searched for : %r ' % request.GET['q'] else:
        message='You submitted an empty form.'
    return HttpResponse(message)

現在就可以顯示用戶搜索的詞。我們可以看到搜索數據在django中的傳遞。

a、在html里定義了一個變量q,當表單提交時,變量q的值通過GET(method="get")附加在URL/search/上。

b、處理/search/的視圖通過request.GET來獲取q的值。明確判斷過q是否包含在request.GET中。

2、接下來從數據庫查詢這個有效的數據。

修改search視圖。

liuxiaoyan@development:~/mysite/books$ cat views.py   
# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponse   
from books.models import Book #記得導入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是否存在於requests.GET並且request.GET['q']是否為空
        q = request.GET['q']
        books = Book.objects.filter(title__icontains=q)#獲取數據庫中包含q的書籍,icontains是一個查詢關鍵字,不區分大小寫 return render_to_response('search_results.html',
            {'books': books, 'query': q})#給模板傳遞一個Book對象列表 else:
        return HttpResponse('Please submit a search term.')

Note:大量數據的數據庫不建議用icontains查詢,因為非常慢。

修改模板

liuxiaoyan@development:~/mysite/templates$ cat search_results.html    
<p>You searched for: <strong>{{ query }}</strong></p>

{% if books %}
    <p>Found {{ books|length }} book{{ books|pluralize }}.</p>
    <ul>
        {% for book in books %}
        <li>{{ book.title }}</li>
        {% endfor %}
    </ul>
{% else %}
    <p>No books matched your search criteria.</p>
{% endif %}

這里pluralize過濾器在適當的時候輸出s(即books)。

結果:

3、改進表單 

現在搜索表單對空字符串的處理相當薄弱,僅顯示一條"Please submit a search term"提示信息,如下圖,若用戶要重新填寫表單必須自行點擊“后退”按鈕,這種做法糟糕又不專業。

在檢查到空字符串時更好的解決方法是重新顯示表單,並在表單上面給出錯誤提示以便用戶立刻重新填寫。最簡單的方法就是添加else分句重新顯示表單。

視圖

liuxiaoyan@development:~/mysite/books$ cat views.py
#
Create your views here. from django.shortcuts import render_to_response from django.http import HttpResponse from 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 HttpResponse('Please submit a search term.')
    #字符串為空時,給search_form.html傳遞一個變量error,並重新顯示
    return render_to_response('search_form.html',{'error':True})

模板:需要檢測error變量,調用search_form視圖時,沒有error變量,所以不會顯示錯誤信息。

liuxiaoyan@development:~/mysite/templates$ cat search_form.html   
<html>
<head>
    <title>Search</title>
</head>
<body> {% if error %} <p style="color: red;">Please submit a search term.</p> {% endif %} <form action="/search/" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>

現在

4、進一步改進表單

沒有必要專門編寫search_form()來顯示表單!!

修改視圖:

liuxiaoyan@development:~/mysite/books$ cat views.py
# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponse   
from books.models import Book

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數據,那么他將看到一個沒有錯誤信息的表單。(因為error=False,'q' in request.GET為假,直接執行最后一行跳轉到search_form.html,且error為假,不顯示提示信息);

如果用戶提交了一個空表單,他將看到錯誤提示信息,還有表單;(因為if not q為真,error被置為真,執行最后一行跳轉到search_form.html,提示出錯i型哪些);

如果用戶提交了一個非空值,他將看到出錯結果。

模板:去掉冗余代碼

liuxiaoyan@development:~/mysite/templates$ cat search_form.html    
<html>
<head>
    <title>Search</title>
</head>
<body>
    {% if error %}
        <p style="color: red;">Please submit a search term.</p>
    {% endif %}
    <form action="" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>

Note:

表單中action="/search/"改為search="",action=""意味着表單將提交給與當前頁面相同的URL。

5、提交數據有效性驗證

在客戶端可用JavaScript對數據進行驗證,同時在服務器端必須再驗證一次,因為有些家伙可能關閉javascript對服務器攻擊。以下介紹的是服務器端的驗證。

改進search()視圖,讓它驗證搜索關鍵字是否小於或者等於20個字符。

修改視圖

最簡單的方式就是將邏輯嵌入到視圖。要注意一點處理多種出錯信息,所以不再使用布爾類型,而用列表來記錄出錯信息。

liuxiaoyan@development:~/mysite/books$ cat views.py
# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponse   
from books.models import Book

def search(request):
   errors=[] if 'q' in request.GET:
        q = request.GET['q']
        if not q:
            errors.append('Enter a search term.')
        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})

修改模板:

liuxiaoyan@development:~/mysite/templates$ cat search_form.html 
<html>
<head>
    <title>Search</title>
</head>
<body>
    {% if errors %}
        <ul>
            {% for error in errors %}
            <li style="color:red">{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    <form action="" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>

視圖根據不同查找信息返回不同錯誤或者結果:

五、POST表單處理的例子

以下開始一個新的例子——站點聯系表單,並且涉及服務器端的操作,所以使用POST,記住一點,我們應該每次都給成功的POST請求做重定向。

因為站點聯系表單跟books模型沒有半毛錢關系,所以我們新建一個contact 的APP。

liuxiaoyan@development:~/mysite$ python manage.py startapp contact

表單功能:用戶反饋,即表單包括用戶提交的反饋信息,一個可選的e-mail回信地址,當這個表單提交並且數據通過驗證后,系統將自動發送一封包含用戶提交信息的e-mail給站點工作人員。【//lxy:其實就是根據用戶提交信息發郵件,郵箱要自己給定】

1、settings.py郵件配置

因為涉及到發郵件,先說一下settings.py郵件相關配置

配置:

首先在MIDDLEWARE_CLASSES中注釋掉'django.middleware.csrf.CsrfViewMiddleware'。

然后配置好郵件代理服務器

#send email 
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST='smtp.126.com' #SMTP服務器
EMAIL_PORT = 25       #SMTP端口
EMAIL_HOST_USER = 'starof@126.com' #用該郵箱發郵件,郵箱必須有效
EMAIL_HOST_PASSWORD = '******'  #郵箱密碼,必須正確
EMAIL_USE_TLS = True #與SMTP服務器通信時,是否啟動TLS連接(安全連接),默認為false

配置好后可以先用一個小demo測試一下:

liuxiaoyan@development:~/mysite$ cat testSendEmail.py
from django.core.mail import send_mail 
from django.http import HttpResponse

def sendEmail(request):
        send_mail('subject', 'this is the message of email', 'starof@126.com', ['reseive@example.com'], fail_silently=True)
        return HttpResponse('successful')

url配置

from testSendEmail import *

 urlpatterns = patterns('',
...
    (r'^mail/$',sendEmail),
...
)

2、站點聯系表單

現在測試我們發郵件成功,說明配置正確,接下來回到contact。先看contact_form.html

liuxiaoyan@development:~/mysite/templates$ cat 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="" method="post">  {% csrf_token %}  <p>Subject:<input type="text" name="subject"></p> <p>Your e-mail (optional):<input type="text" name="email"></p> <p>Message:<textarea name="message" row="10" cols="50"></textarea></p> <input type="submit" value="Submit"> </form> </body> </html>

在視圖中加入

from django.core.mail import send_mail 

liuxiaoyan@development:~/mysite/contact$ cat views.py
# Create your views here.
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext

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']: #弱弱的驗證一下email
            errors.append('Enter a valid e-mail address.')
        if not errors:
            send_mail( #包括主題,正文,寄信人,收信人列表
                request.POST['subject'], #request.POST獲取提交過來的數據
                request.POST['message'],
                #request.POST.get('email', 'starof@126.com'),
                'starof@126.com',  #settings.py中配置的發郵件的郵箱
                ['925xxxx23@qq.com','xxx@xxx.com'], #收郵件的郵箱,可配置多個
                fail_silently=True
            )
            return HttpResponseRedirect('/contact/thanks/') #郵件發送成功重定向頁面 return render_to_response('contact_form.html',{'errors': errors},context_instance=RequestContext(request))
    #return render_to_response('contact_form.html',{'errors': errors})
def thank(request):
    return render_to_response('thank.html')

郵件發送成功為什么用HttpResponseRedirect重定向而不用render_to_response輸出?

如果用戶刷新一個包含POST表單的頁面,那么請求將重新發送造成重復。會造成非期望的結果,比如重復的數據庫記錄,在本例將導致發送兩封同樣的郵件。如果用戶在POST表單之后重定向至另外的頁面,就不會造成重復的請求了。每次都應該給成功的POST做重定向,這是web開發的最佳實踐。

郵件發送后會跳轉到/contact/thanks/的url,

urls.py配置如下:

    (r'^contact/$',contact),
    (r'^contact/thanks/$', thank),

所以再添加一個發郵件成功thank.html模板

liuxiaoyan@development:~/mysite/templates$ cat thank.html 
<html>
<body>
<h2>thank you very much!!!</h2>
</body>
</html>

為了有更好的用戶體驗,讓數據驗證失敗后,返回客戶端的表單中各字段最好是填有原來提交的數據,以便用戶查看哪里出現錯誤(用戶也不需要再次填寫正確的字段值)。手動將原來的提交數據返回給模板。

liuxiaoyan@development:~/mysite/contact$ cat views.py
# Create your views here.
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext

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', 'starof@126.com'),
                'starof@126.com',
                ['xxx@xxx.com','9xxxx3@qq.com'],
                fail_silently=True
            )
            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',''),},context_instance=RequestContext(request))
    #return render_to_response('contact_form.html',{'errors': errors})
def thank(request):
    return render_to_response('thank.html')
View Code

3、可能出現的問題:CSRF verification failed. Request aborted.

解決辦法:

第一步,在template中,為每個POSTform增加一個{% csrf_token %}標簽。如下:

<form>
    {% csrf_token %}
    ...
</form>

第二步,在view中,使用django.template.RequestContext而不是Context。render_to_response,默認使用Context,需要改成RequestContext。RequestContext會處理csrf_token這個tag,自動為表單添加一個名為csrfmiddlewaretoken的input。

具體做法如下:

導入class

from django.template import RequestContext

給render_to_response增加一個參數:

def your_view(request):
    ...
    return render_to_response('template.html',
          your_data,
          context_instance=RequestContext(request)
    )

原理:

  • HTTP響應時django自動添加一個csrftoken到cookie里,值是自動生成的token
  • 所有的POST表單,必須包含一個csrfmiddlewaretoken自動(打tag自動生成)
  • POST提交之前,django驗證cookie里的csrftoken字段的值和提交的表單里的csrfmiddlewaretoken字段的值是否一樣。一樣表明請求合法。否則請求可能來自於別人的csrf攻擊,返回403 Forbidden。

六、在視圖中使用Form對象

Django自帶一個form庫,用做HTML表單顯示以及驗證。就是不用自己寫頁面的form表單,寫個Form類再加一堆使用Form的代碼django 自己給你一個活生生的表單,還能幫你驗證。【//lxy:可能單純的后台程序員會喜歡這樣用,如果習慣寫頁面的人,更傾向於自己寫個fashion的表單自己加js驗證吧,但是存在即合理,看看這個傳說中的djangoForm表單框架吧。此為個人觀點】

1、表單框架的原理

為每一個將要處理的HTML"<Form>" 定義一個Form類,慣例是把Form類都放在一個文件中:forms.py。

liuxiaoyan@development:~/mysite/contact$ cat forms.py
from django import forms

class ContactForm(forms.Form):
    subject=forms.CharField()
    email=forms.EmailField(required=False)
    message=forms.CharField()

表單的每個字段(域)作為Form類的屬性,被展現為Field類。字段默認都是必填的,要讓email可選,特別指定reqired=False。

現在到關鍵時刻了,看看Form框架幕后的工作:

第一步,先看顯示

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from contact.forms import ContactForm
>>> f = ContactForm()
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" id="id_subject" /></td></tr>
<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
>>> 

可以看到Djagno默認用<table>格式輸出表單。

如果用列表ul格式:

>>> print f.as_ul()
<li><label for="id_subject">Subject:</label> <input type="text" name="subject" id="id_subject" /></li>
<li><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>
>>> 

如果用段落p格式:

>>> print f.as_p() 
<p><label for="id_subject">Subject:</label> <input type="text" name="subject" id="id_subject" /></p>
<p><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>
>>> 

快捷顯示

>>> print f['subject']
<input type="text" name="subject" id="id_subject" />
>>> print f['message']
<input type="text" name="message" id="id_message" />
>>> 

第二步,再看校驗數據。

創建一個新的Form對象,並傳入數據。

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from contact.forms import ContactForm
>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})
>>> 

給一個Form實體賦值后,就得到了一個綁定的form,之后在視圖中也會這么用。

>>> f.is_bound
True

調用任何已綁定form的is_valid()方法,就可以指定它的數據是否合法。

現在什么值都給了,當然是合法的了。

>>> f.is_valid()
True

如果不給subject或message賦值,整個Form就不再合法了。

>>> f = ContactForm({'subject': 'Hello'}) 
>>> f.is_valid()
False
>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.is_valid()
False
>>> 

第三步,錯誤消息

接下來看看錯誤消息,可通過每個字段來看,也可直接通過Form實體來看。

逐一查看字段的出錯消息:

>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f['message'].errors
[u'This field is required.']
>>> f['subject'].errors
[]
>>> f['email'].errors
[]
>>> 

因為每個綁定的Form實體都有一個errors屬性,提供一個字段與出錯消息相映射的字典表。之后的模板中會用Form實體的errors屬性去處理錯誤。

>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.errors
{'message': [u'This field is required.']}
>>> 

第四步,cleaned_data

如果一個Form實體的數據是合法的,它就會有一個可用的cleaned_data屬性。這是一個包含干凈的提交數據的字典。Django的Form框架不但校驗數據,還將其轉換成相應的Python類型數據,這叫做清理數據。

>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})  
>>> f.is_valid()
True
>>> f.cleaned_data
{'message': u'Nice site!', 'email': u'adrian@example.com', 'subject': u'Hello'}
>>> 

如果數據不合法會報錯:

>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.is_valid()  
False
>>> f.cleaned_data
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
>>> 

2、在視圖中使用Form對象

djangoForm框架頁沒什么神秘的,使用它將contact視圖改版,確實會輕便不少,如果表單的數據很多的時候其優勢就體現的更明顯。視圖代碼:

liuxiaoyan@development:~/mysite/contact$ cat views.py
# Create your views here.
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from forms import ContactForm #導入ContactForm表單類 def contact(request):
    errors = []
    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','starof@126.com'),
                'starof@126.com',
                ['liuxiaoyan@windawn.com'],
                fail_silently=True
            )
            return HttpResponseRedirect('/contact/thanks/')
    else:
        form=ContactForm()
    return render_to_response('contact_form.html',{'form':form}, context_instance=RequestContext(request))
def thank(request):
    return render_to_response('thank.html')

模板也要稍做處理:

liuxiaoyan@development:~/mysite/templates$ cat 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="/contact/" method="post">
        {% csrf_token %}
        <table>
            {{form.as_table}}
        </table>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

 Django的forms框架處理HTML顯示、數據校驗、數據清理和表單錯誤重現。

看看效果,【//lxy:不得不感嘆真是個丑陋的表單!!!】

驗證效果如下:

發郵件完全正確:

七、 自定義表單框架

以上看到form框架原生的表單是不是丑到沒朋友了。

1、改進字段顯示

message字段被顯示成"input type="text"",而它應該被顯示成<"textarea">。

liuxiaoyan@development:~/mysite/contact$ cat forms.py
from django import forms

class ContactForm(forms.Form):
    subject=forms.CharField()
    email=forms.EmailField(required=False)
    message=forms.CharField(widget=forms.Textarea)

forms框架把每一個字段的顯示邏輯分離到組件(widget)中。每個類型都有一個默認的組件,可以被替換。

Field類表現“校驗邏輯”,部件表現"顯示邏輯"。

2、設置最大長度

liuxiaoyan@development:~/mysite/contact$ cat forms.py
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)

限制subject在100個字符以內。即為CharField提供max_length參數。超過100個字符就沒法輸入了,測試時可將100改為3來試一下。

3、設置初始值

為字段subject添加初始值"I love your site!"。通過在創建Form實體時,使用initial參數。

liuxiaoyan@development:~/mysite/contact$ cat views.py
# Create your views here.
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from forms import ContactForm

def contact(request):
    errors = []
    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','starof@126.com'),
                'starof@126.com',
                ['liuxiaoyan@windawn.com'],
                fail_silently=True
            )
            return HttpResponseRedirect('/contact/thanks/')
    else:
        form=ContactForm(
            initial={'subject':'I love your site!'} #初始設置主題為I love your site!
        )
    return render_to_response('contact_form.html',{'form':form}, context_instance=RequestContext(request))
def thank(request):
    return render_to_response('thank.html')

僅傳入初始值的表單是未綁定狀態的。

4、自定義校驗規則(clean_xxx()方法的用法)

大多數自定義校驗都是一次性的,可以直接綁定到form。給"message"字段額外的校驗,至少有4個單詞。

liuxiaoyan@development:~/mysite/contact$ cat forms.py   
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,at least 4 words!")
        return message

Django的form系統自動尋找以clean_開頭並以字段名稱結束的方法。如果有這樣的方法,它將在默認校驗的之后被調用。

Note:

在函數的末尾顯示返回字段非常重要。如果忘記,原始數據就丟了。即form.cleaned_data['message] 這個值就為None,如果在模板用到這個值就哭去吧。

5、指定標簽

Form表單標簽生成規則為:空格代替下划線,首字母大寫。如email的標簽是"Email"(同樣的邏輯被用於模型(model)中字段的verbose_name值)。現在將email自定義為"Your e-mail address"。

liuxiaoyan@development:~/mysite/contact$ cat forms.py   
from django import forms

class ContactForm(forms.Form):
    subject=forms.CharField(max_length=100)
    email=forms.EmailField(required=False,label='Your e-mail address')
    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,at least 4 words!")
        return message

6、定制Form設計

之前在模板中使用{{form.as_table}}顯示表單,這樣自動生成在開發時快捷方便,但是生產環境,可能想要覆蓋默認的顯示,所以就要重寫。

每一個字段部件(<input type="text">,<select>,<textarea>等)都e抗原通過訪問{{form.字段名}}進行單獨渲染。這里將主動權交到我們手中了。

liuxiaoyan@development:~/mysite/templates$ cat 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">
    {% csrf_token %}
        <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}}會在<ul class="errorlist">里面顯示,如果字段是合法的,或者form沒有被綁定就顯示一個空字符串。【//lxy:該ul是默認的】

可以給它加上css樣式,讓li顯示更突出。

liuxiaoyan@development:~/mysite/templates$ cat contact_form.html
<html>
<head>
    <title>Contact us</title>
<style type="text/css">
    .field{
        bakcground-color:blue;
    }   
    ul{ 
        margin: 0;
        padding: 0;
    }   
    .errorlist li {
        background-color: red;
        color: white;
        display: block;
        font-size: 10px;
        margin: 0 0 3px;
        padding: 4px 5px;
    }   
</style>
</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">
    {% csrf_token %}
        <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>
View Code

下面介紹兩種用法,把form.message.errors當做一個布爾值或者當它是list在上面做迭代。【//lxy:只是說可以這么用,但你不一定要這么用】

liuxiaoyan@development:~/mysite/templates$ cat contact_form.html
<html>
<head>
    <title>Contact us</title>
<style type="text/css">
    .field{
        bakcground-color:blue;
    }   
    ul{ 
        margin: 0;
        padding: 0;
    }   
    .errorlist li {
        background-color: red;
        color: white;
        display: block;
        font-size: 10px;
        margin: 0 0 3px;
        padding: 4px 5px;
    }   
</style>
</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">
    {% csrf_token %}
        <div class="field {% if form.subject.errors %}errorlist{% endif %}">
            {% if form.message.errors %}
                <ul>
                {% for error in form.subject.errors %}                                                                                    
                    <li><strong>{{ error }}</strong></li>
                {% endfor %}
                </ul>
            {% endif %}
            <label for="id_subject">Subject:</label>
            {{ form.subject }}
        </div>
        <div class="field {% if form.email.errors %}errorlist{% endif %}">
            {% if form.message.errors %}
                <ul>
                {% for error in form.email.errors %}
                    <li><strong>{{ error }}</strong></li>
                {% endfor %}
                </ul>
            {% endif %}
            <label for="id_email">Your e-mail address:</label>
            {{ form.email }}
        </div>
        <div class="field {% if form.message.errors %}errorlist{% 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>
        <input type="submit" value="Submit">
    </form>
</body>
</html>
View Code

效果和最后一張圖一樣。

資源鏈接:

http://djangobook.py3k.cn/2.0/chapter07/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM