django框架(2)

cookie和session

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>
View Code

  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>
View Code

  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>
View Code

  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>
View Code

Form組件

功能:(1)對用戶請求的驗證(顯示錯誤信息)

        注意:因爲瀏覽器默認也會對用戶提交的數據作驗證,因此在html表單裏添加novalidate屬性,便可取消瀏覽器端的驗證

           對於form表單,在經過ajax發送請求的時候,獲取表單內容能夠經過$(表單).serialize()獲取該表單內容,發送至後端還是鍵值對格式

   (2)生成html代碼

   (3)HTML Form提交保留上次提交數據

   (4)初始化頁面顯示內容

建立基本form

 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*************************
View 
 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
HTML

  FORM類

建立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     ...
View Code

 注: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對象)將其序列化

相關文章
相關標籤/搜索