提及django表單,那麼就須要深刻理解request這個對象。下面是參考djangobook網站內容,加上本身學習理解後實踐的一些經驗分享。 版本:django2.2.2 + python3.6 。css
1. 關於requesthtml
request.META 是一個Python字典,包含了全部本次HTTP請求的Header信息,好比用戶IP地址和用戶Agent(一般是瀏覽器的名稱和版本號)。 手動寫一個顯示request.META信息的頁面,這樣能夠直觀的看到裏面包含的元素信息, 以下:前端
views.py:python
def display_meta(request): values = request.META.items() values = sorted(values, key=lambda x: x[0]) return render_to_response('display_meta.html', {'meta': values})
urls.py:數據庫
urlpatterns = [ path('admin/', admin.site.urls), path('meta/', views.display_meta), ]
templates/display_meta.html :django
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>request meta</title> </head> <body> <table border="1"> <tr> <th>request</th> <th>info</th> </tr> {% for k, v in meta %} <tr> <td>{{ k }}</td> <td>{{ v }}</td> </tr> {% endfor %} </table> </body> </html>
2. 一個簡單的表單示例瀏覽器
一般,表單開發分爲兩個部分: 前端HTML頁面用戶接口和後臺view函數對所提交數據的處理過程。下面演示一個經過搜索表單來驗證先後臺數據交互處理的示例。app
(1)如今咱們來創建個view來顯示一個搜索表單:books/views.py框架
from django.shortcuts import render_to_response from books.models import Book # Create your views here. 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})
這裏對錶單提交的數據進行了容錯處理,對於輸入錯誤或者不符合條件的給予必定提示。對於提交後的數據經過 title__icontains=q 進行數據庫過濾匹配,匹配到返回數據。ide
(2)前端頁面
templates/search_form.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <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>
templates/search_results.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>results</title> </head> <body> <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 %} </body> </html>
這裏{{ books|length }}和{{ books|pluralize }}是django模板語言特有功能,前面表示計算書的數量,後面是以複數表示出來。
(3)url路徑配置
from django.contrib import admin from django.urls import path from books import views as bk urlpatterns = [ path('admin/', admin.site.urls), path('search/', bk.search), ]
3. 較爲複雜的表單示例
上面表單只包含一個字段 q , 這簡單的例子,咱們不須要使用Django表單庫來處理,可是複雜一點的表單就須要多方面的處理。咱們如今來一下一個較爲複雜的例子:站點聯繫表單,這個表單包括用戶提交的反饋信息,一個可選的e-mail回信地址,當這個表單提交而且數據經過驗證後,系統將自動發送一封包含題用戶提交的信息的e-mail給站點工做人員。
(1)先從前端頁面入手,templates/contact_form.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Contanct us</title> </head> <body> <h1>Contact us</h1> {% if errors %} <ul> {% for error in errors %} <li style="color: red;">{{ error }}</li> {% endfor %} </ul> {% endif %} <form action="/contact/" method="post"> {% csrf_token %} <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>
定義了三個字段:主題、e-mail和反饋信息。除了e-mail字段可選,其餘兩個字段都是必填項。
(2)再來看看視圖的代碼,contact/views.py
#!/usr/bin/python # _*_coding:utf-8_*_ # @Time : 2019/7/4 上午10:47 # @Author : blackysy # @File : views.py.py # @Software : PyCharm 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', 'norepl@example.com'), ['blackysy@qq.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', ''), })
默認GET請求時,會直接返回一個表單頁面給用戶,只有POST纔會進一步處理,由於有必填項,這裏作了些驗證。最後調用send_mail方法發送郵件,發送郵件還須要配置settings.py文件,配置參考以下:
EMAIL_HOST = 'mail.example.com.cn' EMAIL_PORT = 25 EMAIL_HOST_USER = 'blackysy' EMAIL_HOST_PASSWORD = 'blackysy'
(3)最後是url.py
from django.contrib import admin from django.urls import path from spider import views from books import views as bk from contact import views as ct urlpatterns = [ path('admin/', admin.site.urls), path('search/', bk.search), path('contact/', ct.contact), ]
4. 第一個Form類
表單框架最主要的用法是,爲每個將要處理的HTML的 <form> 定義一個Form類。 在這個例子中,咱們只有一個 <form>,所以咱們只需定義一個Form類。 這個類能夠存在於任何地方,甚至直接寫在 views.py 文件裏也行,可是社區的慣例是把Form類都放到一個文件中:forms.py, 在存放 views.py 的目錄中,建立這個文件。這裏建立在contact/forms.py,代碼以下:
from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False, label='E-mail') 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
表單中每個字段做爲Form類的屬性,被展示爲Field類,這裏只使用到CharField和EmailField類。除了email其餘的默認是必填項,經過required=False實現非必填。這裏還加入了自定義規則校驗的方法 clean_message ,校驗提交字數若是小於4個就返回一個錯誤提示。Form表單自定義校驗方法前面必須是 'clean_',後面是具體的字段名稱,必須和上面定義的相同。
另外默認輸出的是table格式,還能夠經過as_ul()、as_p()輸出這兩種格式。標籤<table>、<ul>、<form>的開閉合標記沒有包含於輸出當中,這樣你就能夠添加額外的行或者自定義格式。代碼示例以下:
In [1]: from contact.forms import ContactForm In [2]: f = ContactForm() In [3]: print(f) <tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" required id="id_subject"></td></tr> <tr><th><label for="id_email">Email:</label></th><td><input type="email" name="email" id="id_email"></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" required id="id_message"></td></tr> In [4]: print(f.as_ul()) <li><label for="id_subject">Subject:</label> <input type="text" name="subject" required id="id_subject"></li> <li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email"></li> <li><label for="id_message">Message:</label> <input type="text" name="message" required id="id_message"></li> In [5]: print(f.as_p()) <p><label for="id_subject">Subject:</label> <input type="text" name="subject" required id="id_subject"></p> <p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email"></p> <p><label for="id_message">Message:</label> <input type="text" name="message" required id="id_message"></p>
也能夠單個字段獲取,代碼:
In [6]: print(f['subject']) <input type="text" name="subject" required id="id_subject"> In [7]: print(f['email']) <input type="email" name="email" id="id_email">
Form對象作的第二件事情是校驗數據,下面建立一個新的Form對象,測試代碼以下:
In [8]: f = ContactForm({'subject': 'hello', 'email': 'blackysy@qq.com', 'message': 'Nice site!'}) In [9]: f.is_valid() Out[10]: True In [15]: f = ContactForm({'subject': 'hello', 'message': ''}) In [17]: f.is_valid() Out[17]: False In [18]: f['message'].errors Out[18]: ['This field is required.']
(2)編寫templates/contact_form.html
默認基礎版本的前端頁面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Contanct us</title> </head> <body> <h1>Contact us</h1> {% if form.errors %} <p style="color: red"> Please correct the error{{ forms.errors|pluralize }} below. </p> {% endif %} <form action="" method="post"> <table> {{ form.as_table }} </table> <input type="submit" value="Submit"> </form> </body> </html>
上面的css是默認的,實際咱們都須要自定義表單顯示,因此須要重寫,那麼每個字段部件(<input>, <select>, <textarea>)都經過調用{{ form.字段名 }}進行單獨渲染,因此咱們能夠在這裏自定義。代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Contanct us</title> <style type="text/css"> .field { background-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{{ forms.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">E-mail:</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>
看起來有點難看,但驗證示例將就一下吧~~