在Django框架中編寫Contact表單的教程
雖然我們一直使用書籍搜索的示例表單,并將起改進的很完美,但是這還是相當?shù)暮喡?只包含一個字段,q。這簡單的例子,我們不需要使用Django表單庫來處理。 但是復雜一點的表單就需要多方面的處理,我們現(xiàn)在來一下一個較為復雜的例子: 站點聯(lián)系表單。
這個表單包括用戶提交的反饋信息,一個可選的e-mail回信地址。 當這個表單提交并且數(shù)據(jù)通過驗證后,系統(tǒng)將自動發(fā)送一封包含題用戶提交的信息的e-mail給站點工作人員。
我們從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"> <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> <input type="submit" value="Submit"> </form> </body> </html>
我們定義了三個字段: 主題,e-mail和反饋信息。 除了e-mail字段為可選,其他兩個字段都是必填項。 注意,這里我們使用method=”post”而非method=”get”,因為這個表單會有一個服務(wù)器端的操作:發(fā)送一封e-mail。 并且,我們復制了前一個模板search_form.html中錯誤信息顯示的代碼。
如果我們順著上一節(jié)編寫search()視圖的思路,那么一個contact()視圖代碼應該像這樣:
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})
(如果按照書中的示例做下來,這這里可能乎產(chǎn)生一個疑問:contact()視圖是否要放在books/views.py這個文件里。 但是contact()視圖與books應用沒有任何關(guān)聯(lián),那么這個視圖應該可以放在別的地方? 這毫無緊要,只要在URLconf里正確設(shè)置URL與視圖之間的映射,Django會正確處理的。 筆者個人喜歡創(chuàng)建一個contact的文件夾,與books文件夾同級。這個文件夾中包括空的__init__.py和views.py兩個文件。
現(xiàn)在來分析一下以上的代碼:
確認request.method的值是'POST'。用戶瀏覽表單時這個值并不存在,當且僅當表單被提交時這個值才出現(xiàn)。 (在后面的例子中,request.method將會設(shè)置為'GET',因為在普通的網(wǎng)頁瀏覽中,瀏覽器都使用GET,而非POST)。判斷request.method的值很好地幫助我們將表單顯示與表單處理隔離開來。
我們使用request.POST代替request.GET來獲取提交過來的數(shù)據(jù)。 這是必須的,因為contact_form.html里表單使用的是method=”post”。如果在視圖里通過POST獲取數(shù)據(jù),那么request.GET將為空。
這里,有兩個必填項,subject 和 message,所以需要對這兩個進行驗證。 注意,我們使用request.POST.get()方法,并提供一個空的字符串作為默認值;這個方法很好的解決了鍵丟失與空數(shù)據(jù)問題。
雖然email非必填項,但如果有提交她的值則我們也需進行驗證。 我們的驗證算法相當?shù)谋∪?,僅驗證值是否包含@字符。 在實際應用中,需要更為健壯的驗證機制(Django提供這些驗證機制,稍候我們就會看到)。
我們使用了django.core.mail.send_mail函數(shù)來發(fā)送e-mail。 這個函數(shù)有四個必選參數(shù): 主題,正文,寄信人和收件人列表。 send_mail是Django的EmailMessage類的一個方便的包裝,EmailMessage類提供了更高級的方法,比如附件,多部分郵件,以及對于郵件頭部的完整控制。
注意,若要使用send_mail()函數(shù)來發(fā)送郵件,那么服務(wù)器需要配置成能夠?qū)ν獍l(fā)送郵件,并且在Django中設(shè)置出站服務(wù)器地址。 參見規(guī)范:http://docs.djangoproject.com/en/dev/topics/email/
當郵件發(fā)送成功之后,我們使用HttpResponseRedirect對象將網(wǎng)頁重定向至一個包含成功信息的頁面。 包含成功信息的頁面這里留給讀者去編寫(很簡單 一個視圖/URL映射/一份模板即可),但是我們要解釋一下為何重定向至新的頁面,而不是在模板中直接調(diào)用render_to_response()來輸出。
原因就是: 若用戶刷新一個包含POST表單的頁面,那么請求將會重新發(fā)送造成重復。 這通常會造成非期望的結(jié)果,比如說重復的數(shù)據(jù)庫記錄;在我們的例子中,將導致發(fā)送兩封同樣的郵件。 如果用戶在POST表單之后被重定向至另外的頁面,就不會造成重復的請求了。
我們應每次都給成功的POST請求做重定向。 這就是web開發(fā)的最佳實踐。
contact()視圖可以正常工作,但是她的驗證功能有些復雜。 想象一下假如一個表單包含一打字段,我們真的將必須去編寫每個域?qū)膇f判斷語句?
另外一個問題是表單的重新顯示。若數(shù)據(jù)驗證失敗后,返回客戶端的表單中各字段最好是填有原來提交的數(shù)據(jù),以便用戶查看哪里出現(xiàn)錯誤(用戶也不需再次填寫正確的字段值)。 我們可以手動地將原來的提交數(shù)據(jù)返回給模板,并且必須編輯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', `'noreply@example.com`_'), [`'siteowner@example.com`_'], ) 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"> <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>
這看起來雜亂,且寫的時候容易出錯。 希望你開始明白使用高級庫的用意——負責處理表單及相關(guān)校驗任務(wù)。
相關(guān)文章
python面向?qū)ο蠡A(chǔ)之常用魔術(shù)方法
這是我聽老師上課做的筆記,文中有非常詳細的代碼示例及注釋,對新手及其友好,對正在學習python的小伙伴們也很有幫助,需要的朋友可以參考下2021-05-05在pycharm中運行js文件以及附加node.js下載步驟
js文件需要用node來運行,所以首先要安裝node軟件,下面這篇文章主要給大家介紹了關(guān)于在pycharm中運行js文件以及附加node.js下載步驟的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-12-12Python 執(zhí)行字符串表達式函數(shù)(eval exec execfile)
今天在網(wǎng)上搜尋一些應用的例子時,發(fā)現(xiàn)有人用TK僅僅幾行代碼就寫了個簡易的計算器,驚為天人?;貞浧饎倢W軟件技術(shù)基礎(chǔ)時編寫簡易計算器的艱辛,頓時淚流滿面2014-08-08python3.7環(huán)境下sanic-ext未生效踩坑解析
這篇文章主要為大家介紹了python3.7環(huán)境下sanic-ext未生效踩坑解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01