1.cookie不屬於http協議範圍, 因爲http協議沒法保持狀態, 但實際狀況, 咱們卻又須要"保持狀態",所以cookie就是在這樣一個場景下誕生。css
cookie的工做原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上cookie,這樣服務器就能經過cookie的內容來判斷這個是「誰」了。html
二、cookie雖然在必定程度上解決了「保持狀態」的需求,可是因爲cookie自己最大支持4096字節,以及cookie自己保存在客戶端,可能被攔截或竊取,所以就須要有一種新的東西,它能支持更多的字節,而且他保存在服務器,有較高的安全性。這就是session。前端
問題來了,基於http協議的無狀態特徵,服務器根本就不知道訪問者是「誰」。那麼上述的cookie就起到橋接的做用。python
咱們能夠給每一個客戶端的cookie分配一個惟一的id,這樣用戶在訪問時,經過cookie,服務器就知道來的人是「誰」。而後咱們再根據不一樣的cookie的id,在服務器上保存一段時間的私密資料,如「帳號密碼」等等。jquery
三、總結而言:cookie彌補了http無狀態的不足,讓服務器知道來的人是「誰」;可是cookie以文本的形式保存在本地,自身安全性較差;因此咱們就經過cookie識別不一樣的用戶,對應的在session裏保存私密的信息以及超過4096字節的文本。git
四、另外,上述所說的cookie和session實際上是共通性的東西,不限於語言和框架ajax
前幾節的介紹中咱們已經有能力製做一個登錄頁面,在驗證了用戶名和密碼的正確性後跳轉到後臺的頁面。可是測試後也發現,若是繞過登錄頁面。直接輸入後臺的url地址也能夠直接訪問的。這個顯然是不合理的。其實咱們缺失的就是cookie和session配合的驗證。有了這個驗證過程,咱們就能夠實現和其餘網站同樣必須登陸才能進入後臺頁面了。正則表達式
先說一下這種認證的機制。每當咱們使用一款瀏覽器訪問一個登錄頁面的時候,一旦咱們經過了認證。服務器端就會發送一組隨機惟一的字符串(假設是123abc)到瀏覽器端,這個被存儲在瀏覽端的東西就叫cookie。而服務器端也會本身存儲一下用戶當前的狀態,好比login=true,username=hahaha之類的用戶信息。可是這種存儲是以字典形式存儲的,字典的惟一key就是剛纔發給用戶的惟一的cookie值。那麼若是在服務器端查看session信息的話,理論上就會看到以下樣子的字典數據庫
{'123abc':{'login':true,'username:hahaha'}}django
由於每一個cookie都是惟一的,因此咱們在電腦上換個瀏覽器再登錄同一個網站也須要再次驗證。那麼爲何說咱們只是理論上看到這樣子的字典呢?由於處於安全性的考慮,其實對於上面那個大字典不光key值123abc是被加密的,value值{'login':true,'username:hahaha'}在服務器端也是同樣被加密的。因此咱們服務器上就算打開session信息看到的也是相似與如下樣子的東西
{'123abc':dasdasdasd1231231da1231231}
django的session默認是存儲在數據庫裏的
下面咱們再來最後總結一下cookie和session的知識點
1、操做Cookie
獲取cookie: requst.cookie[key]
設置cookie: response.set_cookie(key,value)
因爲cookie保存在客戶端的電腦上,因此,jquery也能夠操做cookie。
<script src='http://830909.blog.51cto.com/static/js/jquery.cookie.js'></script> $.cookie("list_pager_num", 30,{ path: '/' });
2、操做Session(session默認在服務器端保存15天)
獲取session:request.session[key]
設置session:reqeust.session[key] = value
刪除session:del request.session[key]
(這個刪除其實就是把數據庫的session_data更新爲一個其餘的值了,並無當即刪除)
request.session.set_expiry(value) * 若是value是個整數,session會在些秒數後失效。 * 若是value是個datatime或timedelta,session就會在這個時間後失效。 * 若是value是0,用戶關閉瀏覽器session就會失效。 * 若是value是None,session會依賴全局session失效策略。
1.手動分頁
1 ************************視圖函數**************** 2 uselist = [] 3 for i in range(1,100): 4 use_data ={"username":"root"+str(i),"age":i} 5 uselist.append(use_data) 6 7 def orginal_index(request): 8 per_page_num = 10 #定義每頁顯示的記錄條數 9 current_page = request.GET.get("p") #獲取用戶指定頁碼 10 try: #對用戶輸入的指定頁碼作異常處理,若是小於等於1或者類型錯誤都讓它跳轉至第一頁, 11 current_page = int(current_page) 12 if current_page<=1: 13 current_page = 1 14 except Exception as e: 15 current_page = 1 16 statr_page = (current_page-1)*per_page_num #每頁的開始條數下標 17 end_page = (current_page)*per_page_num #每頁的結束條數下標 18 data = uselist[statr_page:end_page] #切片 19 pre_page = current_page-1 #上一頁頁碼 20 next_page = current_page+1 #下一頁頁碼 21 x,y = divmod(len(uselist),per_page_num) #對分頁的總數作個判斷 22 if y > 0: 23 x = x+1 24 if next_page>x: #若是下一頁的頁碼大於總頁碼讓它跳轉至最後一頁 25 next_page = x 26 return render(request,"orginal_index.html",{"userlist":data,"previous_page":pre_page,"next_page":next_page}) 27 28 29 30 *********************html****************************** 31 <!DOCTYPE html> 32 <html lang="en"> 33 <head> 34 <meta charset="UTF-8"> 35 <title>Title</title> 36 </head> 37 <body> 38 39 <ul> 40 {% for i in userlist%} 41 <li>{{ i.username }}-{{ i.age }}</li> 42 {% endfor %} 43 <p><a href="/orginal_index?p={{ previous_page }}">上一頁</a> 44 <a href="/orginal_index?p={{ next_page }}">下一頁</a></p> 45 </ul> 46 47 </body> 48 </html>
2.django內置分頁
1 *********************視圖函數*********************** 2 # 內置分頁 3 from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage 4 uselist = [] 5 for i in range(1,100): 6 use_data ={"username":"root"+str(i),"age":i} 7 uselist.append(use_data) 8 def inner_index(request): 9 current_page = request.GET.get("p") 10 paginator = Paginator(uselist,10) #建立Paginator對象,第一個參數爲數據源,第二個爲每頁顯示條數 11 # Paginator對象內置方法: 12 # per_page: 每頁顯示條目數量 13 # count: 數據總個數 14 # num_pages:總頁數 15 # page_range:總頁數的索引範圍,如: (1,10),(1,200) 16 # page: page對象(封裝了上一頁,下一頁方法) 17 try: 18 posts = paginator.page(current_page) #調用paginator內置page方法 19 #posts就是page對象,裏面封裝瞭如下方法: 20 # has_next 是否有下一頁 21 # next_page_number 下一頁頁碼 22 # has_previous 是否有上一頁 23 # previous_page_number 上一頁頁碼 24 # object_list 分頁以後的數據列表 ,切片好的數據 25 # number 當前頁 26 # paginator paginator對象 27 except PageNotAnInteger as e: #對用戶傳入的current_page不是整形進行異常處理 28 posts = paginator.page(1) #讓其等於第一頁 29 except EmptyPage: #若是用戶傳入的current_page是一個不存在的頁碼或者空值異常處理 30 posts = paginator.page(paginator.num_pages) #讓其等於最後一頁 31 return render(request,"inner_index.html",{"posts":posts}) 32 33 34 35 ***********************html******************** 36 <!DOCTYPE html> 37 <html lang="en"> 38 <head> 39 <meta charset="UTF-8"> 40 <title>Title</title> 41 </head> 42 <body> 43 44 <ul> 45 {% for i in posts.object_list%} 46 <li>{{ i.username }}-{{ i.age }}</li> 47 {% endfor %} 48 {% if posts.has_previous %} 49 <a href="/inner_index?p={{ posts.previous_page_number }}">上一頁</a> 50 {% else %} 51 <a href="#">上一頁</a> 52 {% endif %} 53 {% if posts.has_next %} 54 <a href="/inner_index?p={{ posts.next_page_number }}">下一頁</a> 55 {% else %} 56 <a href="#">下一頁</a> 57 {% endif %} 58 <span>{{ posts.number }}/{{ posts.paginator.num_pages }}</span> 59 </ul> 60 61 </body> 62 </html>
3.內置分頁擴展
1 ************************視圖函數******************** 2 # 內置分頁拓展 3 from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage 4 uselist = [] 5 for i in range(1,923): 6 use_data ={"username":"root"+str(i),"age":i} 7 uselist.append(use_data) 8 9 class MyPaginator(Paginator): #繼承 10 def __init__(self,current_page,per_page_num,*args,**kwargs): 11 super(MyPaginator,self).__init__(*args,**kwargs) #繼承父類Paingarot方法 12 self.current_page = int(current_page) #當前頁 13 self.per_page_num = int(per_page_num) #每一頁顯示的最多頁碼總數 14 15 def range_index(self): 16 if self.num_pages<self.per_page_num: #若是總頁碼小於每一頁顯示的最多頁碼總數 17 return range(1,self.num_pages+1) 18 part = int(self.per_page_num/2) 19 print(part) 20 print(self.current_page) 21 if self.current_page <= part: #若是當前頁小於等於每頁顯示最多頁碼數的一半 22 return range(1,self.per_page_num+1) 23 if self.current_page+part>self.num_pages: #若是當前頁加每頁顯示最多頁碼數的一半大於總頁碼數 24 return range(self.num_pages-self.per_page_num,self.num_pages+1) 25 return range(self.current_page-part,self.current_page+part+1) 26 def inner_index(request): 27 current_page = request.GET.get("p") 28 paginator = MyPaginator(current_page,11,uselist,10) #建立自定義的繼承類Paingarot方法,第一個參數爲用戶傳入的當前頁碼 29 # ,第二個參數爲每一頁顯示頁碼的數量,第三個參數爲數據源,第四個參數爲每一頁顯示的條數 30 # Paginator對象內置方法: 31 # per_page: 每頁顯示條目數量 32 # count: 數據總個數 33 # num_pages:總頁數 34 # page_range:總頁數的索引範圍,如: (1,10),(1,200) 35 # page: page對象(封裝了上一頁,下一頁方法) 36 try: 37 posts = paginator.page(current_page) #調用paginator內置page方法 38 #posts就是page對象,裏面封裝瞭如下方法: 39 # has_next 是否有下一頁 40 # next_page_number 下一頁頁碼 41 # has_previous 是否有上一頁 42 # previous_page_number 上一頁頁碼 43 # object_list 分頁以後的數據列表 ,切片好的數據 44 # number 當前頁 45 # paginator paginator對象 46 except PageNotAnInteger as e: #對用戶傳入的current_page不是整形進行異常處理 47 posts = paginator.page(1) #讓其等於第一頁 48 except EmptyPage: #若是用戶傳入的current_page是一個不存在的頁碼或者空值異常處理 49 posts = paginator.page(paginator.num_pages) #讓其等於最後一頁 50 return render(request,"inner_index.html",{"posts":posts}) 51 52 53 ***********************html*********************** 54 <!DOCTYPE html> 55 <html lang="en"> 56 <head> 57 <meta charset="UTF-8"> 58 <title>Title</title> 59 </head> 60 <body> 61 62 <ul> 63 {% for i in posts.object_list%} 64 <li>{{ i.username }}-{{ i.age }}</li> 65 {% endfor %} 66 {% if posts.has_previous %} 67 <a href="/inner_index?p={{ posts.previous_page_number }}">上一頁</a> 68 {% else %} 69 <a href="#">上一頁</a> 70 {% endif %} 71 {% for v in posts.paginator.range_index %} 72 {% if posts.number == v %} 73 <a style="font-size: 60px" href="/inner_index?p={{ v }}">{{ v }}</a> 74 {% else %} 75 <a href="/inner_index?p={{ v }}">{{ v }}</a> 76 {% endif %} 77 {% endfor %} 78 {% if posts.has_next %} 79 <a href="/inner_index?p={{ posts.next_page_number }}">下一頁</a> 80 {% else %} 81 <a href="#">下一頁</a> 82 {% endif %} 83 <span>{{ posts.number }}/{{ posts.paginator.num_pages }}</span> 84 </ul> 85 86 </body> 87 </html>
4.自定義分頁組件
因爲django分頁時對數據有延遲加載,因此當數據源比較大時,django內置的分頁組件仍然適用,但其餘框架裏不必定有延遲加載,因此當數據源比較大時,若是每次分頁時都調用整個數據庫的數據,顯然是不合適的,因此咱們能夠經過切片方式自定義分頁組件,適用任何框架
1 ***************views.py********************* 2 3 from app01.diy_per_page import * #diy_per_page爲咱們本身單獨寫的分頁組件文件 4 uselist = [] 5 for i in range(1,923): 6 use_data ={"username":"root"+str(i),"age":i} 7 uselist.append(use_data) 8 9 def diy_index(request): 10 current_page = request.GET.get("p") 11 obj = Diy_page(len(uselist),current_page,10,11) 12 data = uselist[obj.start_page():obj.end_page()] 13 return render(request,"diy_index.html",{"object_list":data,"obj":obj}) 14 15 *****************diy_per_page.py****************** 16 class Diy_page(object): 17 def __init__(self,total_count,current_page,per_page_num,max_page_num): 18 # 數據源總記錄條數 19 self.total_count = total_count 20 # 接收用戶發送的當前頁碼 21 try: 22 v = int(current_page) 23 if v<=0: #若是用戶輸入的頁碼小於1,直接讓它等於1 24 v = 1 25 self.current_page = v 26 except Exception as e: 27 self.current_page = 1 28 # 每一頁顯示的記錄條數 29 self.per_page_num = per_page_num 30 # 每一頁顯示的最多頁碼數 31 self.max_page_num = max_page_num 32 @property 33 def num_pages(self): 34 ''' 35 總頁碼數 36 :return: 37 ''' 38 a,b = divmod(self.total_count,self.per_page_num) 39 if b == 0: 40 return a 41 else: 42 return a+1 43 def page_range(self): 44 ''' 45 每一頁所能顯示的最多頁碼數範圍 46 :return: 47 ''' 48 if self.num_pages<self.max_page_num: #若是總頁碼小於每一頁顯示的最多頁碼總數 49 return range(1,self.num_pages+1) 50 part = int(self.max_page_num/2) 51 if self.current_page <= part: #若是當前頁小於等於每頁顯示最多頁碼數的一半 52 return range(1,self.max_page_num+1) 53 if self.current_page+part>self.num_pages: #若是當前頁加每頁顯示最多頁碼數的一半大於總頁碼數 54 return range(self.num_pages-self.max_page_num,self.num_pages+1) 55 return range(self.current_page-part,self.current_page+part+1) 56 def start_page(self): 57 ''' 58 切片的起始位置 59 :return: 60 ''' 61 return (self.current_page-1)*self.per_page_num 62 def end_page(self): 63 ''' 64 切片的結束位置 65 :return: 66 ''' 67 return self.current_page*self.per_page_num 68 def a_num_pages(self): 69 ''' 70 每一頁底部頁碼連接標籤 71 :return: 72 ''' 73 li = [] 74 head_page = "<li><a href='/diy_index?p=1'>首頁</a></li>" 75 li.append(head_page) 76 if self.current_page ==1: 77 prev_page = "<li><a href='#'>上一頁</a></li>" #生成上一頁標籤 78 else: 79 prev_page = "<li><a href='/diy_index?p=%s'>上一頁</a></li>"%(self.current_page-1) 80 li.append(prev_page) 81 for row in self.page_range(): 82 if row == self.current_page: 83 data = "<li class='active'><a href='/diy_index?p=%s'>%s</a></li>"%(row,row) 84 else: 85 data = "<li><a href='/diy_index?p=%s'>%s</a></li>" % (row, row) 86 li.append(data) 87 if self.current_page ==self.num_pages: 88 next_page = "<li><a href='#'>下一頁</a></li>" #生成下一頁標籤 89 else: 90 next_page = "<li><a href='/diy_index?p=%s'>下一頁</a><li>"%(self.current_page+1) 91 li.append(next_page) 92 last_page = "<li><a href='/diy_index?p=%s'>尾頁</a><li>"%self.num_pages 93 li.append(last_page) 94 return "".join(li) #返回前端是拼接的字符串 95 96 97 ***************html************************** 98 <!DOCTYPE html> 99 <html lang="en"> 100 <head> 101 <meta charset="UTF-8"> 102 <title>Title</title> 103 <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"> #爲了格式好看,咱們引入bootstrap文件,調用其分頁插件,相應標籤屬性對應修改,在此不加詳細闡述 104 </head> 105 <body> 106 107 <ul> 108 {% for i in object_list%} 109 <li>{{ i.username }}-{{ i.age }}</li> 110 {% endfor %} 111 112 <ul class="pagination"> 113 {{ obj.a_num_pages|safe }} 114 </ul> 115 </ul> 116 117 </body> 118 </html>
功能:(1)對用戶請求的驗證(顯示錯誤信息)
注意:因爲瀏覽器默認也會對用戶提交的數據作驗證,因此在html表單裏添加novalidate屬性,便可取消瀏覽器端的驗證
對於form表單,在經過ajax發送請求的時候,獲取表單內容能夠經過$(表單).serialize()獲取該表單內容,發送至後端還是鍵值對格式
(2)生成html代碼
(3)HTML Form提交保留上次提交數據
(4)初始化頁面顯示內容
1 ********************form類**************** 2 3 from django.shortcuts import render,HttpResponse,redirect 4 from django import forms 5 from django.forms import fields 6 from app02 import models 7 # Create your views here. 8 9 10 class Myform(forms.Form): #定義form類 11 username = fields.CharField( 12 required=True, 13 max_length=32, 14 min_length=6, 15 label="用戶名", 16 initial="請輸入用戶名", 17 error_messages={ 18 "required":"不能爲空", #用定義的屬性字段來定義錯誤信息 19 "invalid":"格式錯誤" #格式錯誤都用invalid定義 20 } 21 22 ) 23 passwd = fields.IntegerField( 24 required=True, 25 label="密碼" 26 ) 27 e_mail = fields.EmailField( 28 required=True, 29 label="郵箱" 30 31 32 ) 33 34 ****************views處理函數************* 35 def myform1(request): 36 user_list = models.User_info.objects.all() 37 return render(request,"my_form1.html",{"user_list":user_list}) 38 39 def add_user(request): 40 if request.method == "GET": 41 obj = Myform() #此處實例化form對象,對象裏的字段能夠經過靜態方法調用,且在前端調用時會執行內部的__str__()方法,生成對應的標籤 42 return render(request,"add_user.html",{"obj":obj}) 43 else: 44 obj = Myform(request.POST) #此處會將前端接收的數據傳遞給form類,此時並不會進行驗證 45 if obj.is_valid(): #此處進行驗證 46 models.User_info.objects.create(**obj.cleaned_data) #cleaned_data爲驗證過的用戶數據,爲字典格式 47 return redirect("/my_form1") 48 else: 49 return render(request,"add_user.html",{"obj":obj}) 50 51 def edit_user(request): 52 nid = request.GET.get("p") 53 if request.method == "GET": 54 obj = models.User_info.objects.filter(id = nid).first() 55 data = Myform({"username":obj.username,"passwd":obj.passwd,"e_mail":obj.e_mail}) #實例化時傳入自定義字典能夠在前端設置默認值,字段要跟form對應上 56 return render(request,"edit_user.html",{"data":data,"nid":nid}) 57 58 else: 59 data = Myform(request.POST) 60 if data.is_valid(): 61 models.User_info.objects.filter(id = nid).update(**data.cleaned_data) 62 return redirect("/my_form1") 63 else: 64 return render(request,"edit_user.html",{"data":data,"nid":nid}) 65 66 67 68 ********************html*************************
1 **************my_form1**************** 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <a href="/add_user">添加</a> 9 <ul> 10 {% for row in user_list %} 11 <li>{{ row.username }}-{{ row.passwd }}-{{ row.e_mail }} <a href="/edit_user?p={{ row.id }}">修改</a></li> 12 {% endfor %} 13 </ul> 14 15 </body> 16 </html> 17 18 19 ****************edit_user******************* 20 <!DOCTYPE html> 21 <html lang="en"> 22 <head> 23 <meta charset="UTF-8"> 24 <title>Title</title> 25 </head> 26 <body> 27 28 <form action="/edit_user?p={{ nid }}" method="post" novalidate> 29 {% csrf_token %} 30 <p>{{ data.username.label }}{{ data.username }}{{ data.username.errors.0 }}</p> 31 <p>{{ data.passwd.label }}{{ data.passwd }}{{ data.passwd.errors.0 }}</p> 32 <p>{{ data.e_mail.label }}{{ data.e_mail }}{{ data.e_mail.errors.0 }}</p> 33 <p><input type="submit"></p> 34 </form> 35 36 </body> 37 </html> 38 39 ***************add_user********************* 40 <!DOCTYPE html> 41 <html lang="en"> 42 <head> 43 <meta charset="UTF-8"> 44 <title>Title</title> 45 </head> 46 <body> 47 <form action="/add_user" method="post" novalidate> 48 {% csrf_token %} 49 <p>{{ obj.username.label }}{{ obj.username }}{{ obj.username.errors.0 }}</p> 50 <p>{{ obj.passwd.label }}{{ obj.passwd }}{{ obj.passwd.errors.0 }}</p> 51 <p>{{ obj.e_mail.label }}{{ obj.e_mail }}{{ obj.e_mail.errors.0 }}</p> 52 <p><input type="submit"></p> 53 </form> 54 55 </body> 56 </html> 57 58 html
建立Form類時,主要涉及到字段和插件,字段用於對用戶請求數據的驗證,插件用於自動生成HTML
1, django內置字段:
1 Field 2 required=True, 是否容許爲空 3 widget=None, HTML插件 4 label=None, 用於生成Label標籤或顯示內容 5 initial=None, 初始值 6 help_text='', 幫助信息(在標籤旁邊顯示) 7 error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} 8 show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直) 9 validators=[], 自定義驗證規則 10 localize=False, 是否支持本地化 11 disabled=False, 是否能夠編輯 12 label_suffix=None Label內容後綴 13 14 15 CharField(Field) 16 max_length=None, 最大長度 17 min_length=None, 最小長度 18 strip=True 是否移除用戶輸入空白 19 20 IntegerField(Field) 21 max_value=None, 最大值 22 min_value=None, 最小值 23 24 FloatField(IntegerField) 25 ... 26 27 DecimalField(IntegerField) 28 max_value=None, 最大值 29 min_value=None, 最小值 30 max_digits=None, 總長度 31 decimal_places=None, 小數位長度 32 33 BaseTemporalField(Field) 34 input_formats=None 時間格式化 35 36 DateField(BaseTemporalField) 格式:2015-09-01 37 TimeField(BaseTemporalField) 格式:11:12 38 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 39 40 DurationField(Field) 時間間隔:%d %H:%M:%S.%f 41 ... 42 43 RegexField(CharField) 44 regex, 自定製正則表達式 45 max_length=None, 最大長度 46 min_length=None, 最小長度 47 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} 48 49 EmailField(CharField) 50 ... 51 52 FileField(Field) 53 allow_empty_file=False 是否容許空文件 54 55 ImageField(FileField) 56 ... 57 注:須要PIL模塊,pip3 install Pillow 58 以上兩個字典使用時,須要注意兩點: 59 - form表單中 enctype="multipart/form-data" 60 - view函數中 obj = MyForm(request.POST, request.FILES) 61 62 URLField(Field) 63 ... 64 65 66 BooleanField(Field) 67 ... 68 69 NullBooleanField(BooleanField) 70 ... 71 72 ChoiceField(Field) 73 ... 74 choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) 75 required=True, 是否必填 76 widget=None, 插件,默認select插件 77 label=None, Label內容 78 initial=None, 初始值 79 help_text='', 幫助提示 80 81 82 ModelChoiceField(ChoiceField) 83 ... django.forms.models.ModelChoiceField 84 queryset, # 查詢數據庫中的數據 85 empty_label="---------", # 默認空顯示內容 86 to_field_name=None, # HTML中value的值對應的字段 87 limit_choices_to=None # ModelForm中對queryset二次篩選 88 89 ModelMultipleChoiceField(ModelChoiceField) 90 ... django.forms.models.ModelMultipleChoiceField 91 92 93 94 TypedChoiceField(ChoiceField) 95 coerce = lambda val: val 對選中的值進行一次轉換 96 empty_value= '' 空值的默認值 97 98 MultipleChoiceField(ChoiceField) 99 ... 100 101 TypedMultipleChoiceField(MultipleChoiceField) 102 coerce = lambda val: val 對選中的每個值進行一次轉換 103 empty_value= '' 空值的默認值 104 105 ComboField(Field) 106 fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式 107 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 108 109 MultiValueField(Field) 110 PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用 111 112 SplitDateTimeField(MultiValueField) 113 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 114 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 115 116 FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 117 path, 文件夾路徑 118 match=None, 正則匹配 119 recursive=False, 遞歸下面的文件夾 120 allow_files=True, 容許文件 121 allow_folders=False, 容許文件夾 122 required=True, 123 widget=None, 124 label=None, 125 initial=None, 126 help_text='' 127 128 GenericIPAddressField 129 protocol='both', both,ipv4,ipv6支持的IP格式 130 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用 131 132 SlugField(CharField) 數字,字母,下劃線,減號(連字符) 133 ... 134 135 UUIDField(CharField) uuid類型 136 ...
注:UUID是個根據MAC以及當前時間等建立的不重複的隨機字符串
2, django內置插件
1 TextInput(Input) 2 NumberInput(TextInput) 3 EmailInput(TextInput) 4 URLInput(TextInput) 5 PasswordInput(TextInput) 6 HiddenInput(TextInput) 7 Textarea(Widget) 8 DateInput(DateTimeBaseInput) 9 DateTimeInput(DateTimeBaseInput) 10 TimeInput(DateTimeBaseInput) 11 CheckboxInput 12 Select 13 NullBooleanSelect 14 SelectMultiple 15 RadioSelect 16 CheckboxSelectMultiple 17 FileInput 18 ClearableFileInput 19 MultipleHiddenInput 20 SplitDateTimeWidget 21 SplitHiddenDateTimeWidget 22 SelectDateWidget
1 # 單radio,值爲字符串 2 # user = fields.CharField( 3 # initial=2, 4 # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) 5 # ) 6 7 # 單radio,值爲字符串 8 # user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 # initial=2, 11 # widget=widgets.RadioSelect 12 # ) 13 14 # 單select,值爲字符串 15 # user = fields.CharField( 16 # initial=2, 17 # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) 18 # ) 19 20 # 單select,值爲字符串 21 # user = fields.ChoiceField( 22 # choices=((1, '上海'), (2, '北京'),), 23 # initial=2, 24 # widget=widgets.Select 25 # ) 26 27 # 多選select,值爲列表 28 # user = fields.MultipleChoiceField( 29 # choices=((1,'上海'),(2,'北京'),), 30 # initial=[1,], 31 # widget=widgets.SelectMultiple 32 # ) 33 34 35 # 單checkbox 36 # user = fields.CharField( 37 # widget=widgets.CheckboxInput() 38 # ) 39 40 41 # 多選checkbox,值爲列表 42 # user = fields.MultipleChoiceField( 43 # initial=[2, ], 44 # choices=((1, '上海'), (2, '北京'),), 45 # widget=widgets.CheckboxSelectMultiple 46 # )
在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段 ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from django.core.validators import RegexValidator 5 6 class MyForm(Form): 7 8 user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 initial=2, 11 widget=widgets.Select 12 ) 13 14 def __init__(self, *args, **kwargs): 15 super(MyForm,self).__init__(*args, **kwargs) #注意此句跟下句位置不能調換,super方法的做用至關於將form類的全部靜態字段加載到內存,而後下一句fields對象才能找到對應的字段 16 # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),) 17 # 或 18 self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
方式二:
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現
1 from django import forms 2 3 from django.forms import fields 4 from django.forms import widgets 5 from django.forms import models as form_model #須要導入此模塊 6 from django.core.exceptions import ValidationError 7 from django.core.validators import RegexValidator 8 9 class FInfo(forms.Form): 10 authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) 11 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) #注意因爲前端調用的時候是調用的字段對象方法,因此要顯示對象的值須要在model對應的類中定義__str()__方法,返回類的字段
方法一:
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from django.core.validators import RegexValidator 5 6 class MyForm(Form): 7 user = fields.CharField( 8 validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')], 9 )
方法二:
1 import re 2 from django.forms import Form 3 from django.forms import widgets 4 from django.forms import fields 5 from django.core.exceptions import ValidationError #需導入 6 7 8 # 自定義驗證規則 9 def mobile_validate(value): 10 mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') 11 if not mobile_re.match(value): 12 raise ValidationError('手機號碼格式錯誤') 13 14 15 class PublishForm(Form): 16 17 18 title = fields.CharField(max_length=20, 19 min_length=5, 20 error_messages={'required': '標題不能爲空', 21 'min_length': '標題最少爲5個字符', 22 'max_length': '標題最多爲20個字符'}, 23 widget=widgets.TextInput(attrs={'class': "form-control", 24 'placeholder': '標題5-20個字符'})) 25 26 27 # 使用自定義驗證規則 28 phone = fields.CharField(validators=[mobile_validate, ], 29 error_messages={'required': '手機不能爲空'}, 30 widget=widgets.TextInput(attrs={'class': "form-control", 31 'placeholder': u'手機號碼'})) 32 33 email = fields.EmailField(required=False, 34 error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'}, 35 widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))
方法三:自定義方法
1 from django import forms 2 from django.forms import fields 3 from django.forms import widgets 4 from django.core.exceptions import ValidationError 5 from django.core.validators import RegexValidator 6 7 class FInfo(forms.Form): 8 username = fields.CharField(max_length=5, 9 validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], ) 10 email = fields.EmailField() 11 12 def clean_username(self): #clean_+字段名(固定格式),因爲字典無序,只能對當前本身字段進行驗證,驗證過程當中不能涉及其餘字段 13 """ 14 Form中字段中定義的格式匹配完以後,執行此方法進行驗證 15 :return: 16 """ 17 value = self.cleaned_data['username'] #從字段與對應的值組成的字典中取出對應的值 18 if "666" in value: 19 raise ValidationError('666已經被玩爛了...', 'invalid') #引起特定異常,第一個參數爲錯誤信息提示,第二個爲錯誤類型,不定義默認用invalid 20 return value #必須有返回值,若是驗證經過,字典中對應的該字段至關於從新進行了賦值,但值沒改
方法四:自定義總體驗證
1 from django.core.exceptions import ValidationError 2 class Form_diy(forms.Form): 3 username = fields.CharField(max_length=32) 4 user_id = fields.IntegerField() 5 def clean(self): #clean名字固定,此時全部字段已執行完單獨的驗證 6 value_dict = self.cleaned_data #包含全部的用戶提交過來的信息 7 v1 = value_dict["username"] 8 v2 = value_dict["user_id"] 9 if v1 == "eric" and v2 == 12: #自定義驗證 10 raise ValidationError("總體信息錯誤") #拋出異常 11 ''' 12 注意:此處拋出的錯誤信息會被放進errors字典裏面,且鍵爲__all__ 13 errors錯誤信息的字典格式爲 14 { 15 __all__:["總體錯誤信息",], 16 字段一:[mes1,mes2,], 17 字段二:[mes1,mes2,], 18 } 19 ''' 20 return value_dict
方法五:同時生成多個標籤驗證
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 5 from django.core.validators import RegexValidator 6 7 8 ############## 自定義字段 ############## 9 class PhoneField(fields.MultiValueField): 10 def __init__(self, *args, **kwargs): 11 # Define one message for all fields. 12 error_messages = { 13 'incomplete': 'Enter a country calling code and a phone number.', 14 } 15 # Or define a different message for each field. 16 f = ( 17 fields.CharField( 18 error_messages={'incomplete': 'Enter a country calling code.'}, 19 validators=[ 20 RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'), 21 ], 22 ), 23 fields.CharField( 24 error_messages={'incomplete': 'Enter a phone number.'}, 25 validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')], 26 ), 27 fields.CharField( 28 validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')], 29 required=False, 30 ), 31 ) 32 super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args, 33 **kwargs) 34 35 def compress(self, data_list): 36 """ 37 當用戶驗證都經過後,該值返回給用戶 38 :param data_list: 39 :return: 40 """ 41 return data_list 42 43 ############## 自定義插件 ############## 44 class SplitPhoneWidget(widgets.MultiWidget): 45 def __init__(self): 46 ws = ( 47 widgets.TextInput(), 48 widgets.TextInput(), 49 widgets.TextInput(), 50 ) 51 super(SplitPhoneWidget, self).__init__(ws) 52 53 def decompress(self, value): 54 """ 55 處理初始值,當初始值initial不是列表時,調用該方法 56 :param value: 57 :return: 58 """ 59 if value: 60 return value.split(',') 61 return [None, None, None]
簡單來講,序列化就是把某種東西轉化成可以能夠保存在文件裏的過程,叫作序列化,反之即反序列化
json只能序列化python基本的數據類型
經過ajax發送數據的時候,若是數據裏面有列表,加入traditional:True,防止jquery會深度序列化參數對象
對於django特有的queryset對象。須要用serializers.serializers("json",queryset對象)將其序列化