django book2 表單學習筆記

風之諾發表於2014-02-25
form = ProductForm(request.POST or None):python or 含義:如果第1個為真,返回第1個,否則返回第2個


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






from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
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', 'noreply@example.com'),
                ['siteowner@example.com'],
            )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html',
        {'errors': errors})
        
當郵件傳送成功之後,我們使用HttpResponseRedirect物件將網頁重定向至一個包含成功資訊的頁面。 包
含成功資訊的頁面這裡留給讀者去編寫(很簡單 一個檢視/URL對映/一份模板即可),但是我們要解釋一
下為何重定向至新的頁面,而不是在模板中直接呼叫render_to_response()來輸出。


原因就是: 若使用者重新整理一個包含POST表單的頁面,那麼請求將會重新傳送造成重複。 這通常會造成非期望
的結果,比如說重複的資料庫記錄;在我們的例子中,將導致傳送兩封同樣的郵件。 如果使用者在POST表單
之後被重定向至另外的頁面,就不會造成重複的請求了。
我們應每次都給成功的POST請求做重定向。 這就是web開發的最佳實踐。




1)Python直譯器裡面看看這個類做了些什麼。 它做的第一件事是將自己顯示成HTML:
>>> 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_
<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email"
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_




Form物件做的第二件事是校驗資料。 為了校驗資料,我們建立一個新的對Form象,並且傳入一個與定義匹配的
字典型別資料:
>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})
一旦你對一個Form實體賦值,你就得到了一個繫結form:
>>> f.is_bound
obook.py3k.cn/2.0/chapter07/12/182010-5-5第七章:表單
True
呼叫任何繫結form的is_valid()方法,就可以知道它的資料是否合法。 我們已經為每個欄位傳入了值,因此整
個Form是合法的:
>>> f.is_valid()
True




每一個邦定Form實體都有一個errors屬性,它為你提供了一個欄位與錯誤訊息相對映的字典表。
>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.errors
{'message': [u'This field is required.']}


最終,如果一個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': uNice site!, email: uadrian@example.com, subject: uHello}








在檢視中使用Form物件


from django.shortcuts import render_to_response
from mysite.contact.forms import ContactForm
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', 'noreply@example.com'),
                ['siteowner@example.com'],
            )
            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>
看看,我們能移除這麼多不整齊的程式碼! Django的forms框架處理HTML顯示、資料校驗、資料清理和表單錯
誤重現。




1 改變欄位顯示
    你可能首先注意到:當你在本地顯示這個表單的時,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** )
    obook.py3k.cn/2.0/chapter07/14/182010-5-5第七章:表單
    forms框架把每一個欄位的顯示邏輯分離到一組部件(widget)中。 每一個欄位型別都擁有一個預設的部件,
    我們也可以容易地替換掉預設的部件,或者提供一個自定義的部件。
    考慮一下Field類表現* 校驗邏輯* ,而部件表現* 顯示邏輯* 。
2 設定最大長度
    一個最經常使用的校驗要求是檢查欄位長度。 另外,我們應該改進ContactForm,使subject限制在100個字元
    以內。 為此,僅需為CharField提供max_length引數,像這樣:
    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)
    選項min_length引數同樣可用。
3 設定初始值
    讓我們再改進一下這個表單:為字subject段新增* 初始值* : "I love your site!" (一點建議,但沒壞處。
    )為此,我們可以在建立Form實體時,使用initial引數:
    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', `'noreply@example.com`_'),
                    [`'siteowner@example.com`_'],
                )
                return HttpResponseRedirect('/contact/thanks/')
        else:
            form = ContactForm(
                **initial={'subject': 'I love your site!'}**
            )
        return render_to_response('contact_form.html', {'form': form})
    現在,subject欄位將被那個句子填充。
    請注意,傳入* 初始值* 資料和傳入資料以* 繫結* 表單是有區別的。 最大的區別是,如果僅傳入* 初始值* 數
    據,表單是unbound的,那意味著它沒有錯誤訊息。
4 自定義校驗規則
    假設我們已經發布了反饋頁面了,email已經開始源源不斷地湧入了。 這裡有一個問題: 一些提交的訊息只有
    一兩個字,我們無法得知詳細的資訊。 所以我們決定增加一條新的校驗: 來點專業精神,最起碼寫四個字,拜
    託。
    我們有很多的方法把我們的自定義校驗掛在Django的form上。 如果我們的規則會被一次又一次的使用,我們
    可以建立一個自定義的欄位型別。 大多數的自定義校驗都是一次性的,可以直接繫結到form類.
    djangobook.py3k.cn/2.0/chapter07/15/182010-5-5第七章:表單
    我們希望`` message`` 欄位有一個額外的校驗,我們增加一個`` clean_message()`` 方法到`` Form`` 類:
    1from 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
    Django的form系統自動尋找匹配的函式方法,該方法名稱以clean_開頭,並以欄位名稱結束。 如果有這樣
    方法,它將在校驗時被呼叫。
    特別地,clean_message()方法將在指定欄位的預設校驗邏輯執行* 之後* 被呼叫。(本例中,在必
    填CharField這個校驗邏輯之後。)因為欄位資料已經被部分處理,所以它被從self.cleaned_data中提取出來
    了。同樣,我們不必擔心資料是否為空,因為它已經被校驗過了。
    我們簡單地使用了len()和split()的組合來計算單詞的數量。 如果使用者輸入字數不足,我們丟擲一
    個forms.ValidationError型異常。這個異常的描述會被作為錯誤列表中的一項顯示給使用者。
    在函式的末尾顯式地返回欄位的值非常重要。 我們可以在我們自定義的校驗方法中修改它的值(或者把它轉換
    成另一種Python型別)。 如果我們忘記了這一步,None值就會返回,原始的資料就丟失掉了。
    
 5 指定標籤
    HTML表單中自動生成的標籤預設是按照規則生成的:用空格代替下劃線,首字母大寫。如email的標籤
    是"Email" 。(好像在哪聽到過? 是的,同樣的邏輯被用於模組(model)中欄位的verbose_name值。 我們在
    第五章談到過。)
    像在模組中做過的那樣,我們同樣可以自定義欄位的標籤。 僅需使用label,像這樣:
    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)
        
        
6 定製Form設計
    在上面的`` contact_form.html`` 模板中我們使用`` {{form.as_table}}`` 顯示錶單,不過我們可以使用其他更精
    確控制表單顯示的方法。
    修改form的顯示的最快捷的方式是使用CSS。 尤其是錯誤列表,可以增強視覺效果。自動生成的錯誤列表精確
    的使用`` <ul class=”errorlist”>``,這樣,我們就可以針對它們使用CSS。 下面的CSS讓錯誤更加醒目了:
    <style type="text/css">
        ul.errorlist {
            margin: 0;
            padding: 0;
        }
        .errorlist li {
            background‐color: red;
            display: block;
            font‐size: 10px;
            margin: 0 0 3px;
            padding: 4px 5px;
        }
    </style>
    雖然,自動生成HTML是很方便的,但是在某些時候,你會想覆蓋預設的顯示。 {{form.as_table}}和其它的方
    法在開發的時候是一個快捷的方式,form的顯示方式也可以在form中被方便地重寫。
    每一個欄位部件(<input type=”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 }} 會在 <ul class="errorlist"> 裡面顯示,如果欄位是合法的,或者form沒有被綁
    定,就顯示一個空字串。 我們還可以把 form.message.errors 當作一個布林值或者當它是list在上面做迭代,
    例如:
    <div class="field{% if form.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>


    Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
    This work is licensed under the GNU Free Document License. 
    Hosting graciously provided by  
    Chinese translate hosting by py3k.cn.
    Document License`_.
        {{ form.message }}
    </div>
    在校驗失敗的情況下, 這段程式碼會在包含錯誤欄位的div的class屬性中增加一個”errors”,在一個有序列表中
    顯示錯誤資訊。

相關文章