課程介紹
MVC
MVC框架的核心思想是:解耦,讓不同的程式碼塊之間降低耦合,增強程式碼的可擴充套件性和可移植性,實現向後相容
- M:Model,主要封裝對資料庫層的訪問,對資料庫中的資料進行增、刪、改、查操作
- V:View,用於封裝結果,生成頁面展示的html內容
- C:Controller,用於接收請求,處理業務邏輯,與Model和View互動,返回結果
Django-MVT
- M:Model,與MVC中的M功能相同,負責和資料庫互動,進行資料處理
- V:View,與MVC中的C功能相同,接收請求,進行業務處理,返回應答
- T:Template,與MVC中的V功能相同,負責封裝構造要返回的html
MVVM
- 出現原因:由於前端開發混合了HTML、CSS和JavaScript,而且頁面眾多,所以,程式碼的組織和維護難度其實更加複雜
- 好處:改變JavaScript物件的狀態,會導致DOM結構作出對應的變化,關注點就從如何操作DOM變成了如何更新JavaScript物件的狀態
- MVVM的設計思想:關注Model的變化,讓MVVM框架去自動更新DOM的狀態,從而把開發者從操作DOM的繁瑣步驟中解脫出來
- 結構:借鑑桌面應用程式的MVC思想,在前端頁面中,把Model用純JavaScript物件表示,View負責顯示,兩者做到了最大限度的分離
- 使用:把Model和View關聯起來的就是ViewModel。ViewModel負責把Model的資料同步到View顯示出來,還負責把View的修改同步回Model
入門
設計模型
ORM框架
- O是object,也就類物件的意思
- R是relation,翻譯成中文是關係,也就是關聯式資料庫中資料表的意思
- M是mapping,是對映的意思
在ORM框架中,它幫我們把類和資料表進行了一個對映,可以讓我們通過類和類物件就能操作它所對應的表格中的資料。ORM框架還有一個功能,它可以根據我們設計的類自動幫我們生成資料庫中的表格,省去了我們自己建表的過程
- 使用django進行資料庫開發的步驟如下
- 在models.py中定義模型類
- 遷移
- 通過類和物件完成資料增刪改查操作
說明:不需要定義主鍵列,在生成時會自動新增,並且值為自動增長
資料表的預設名稱為:<app_name>_<model_name>
一對多的關係(ForeignKey)應定義在多的那個類中
管理站點
註冊模型類
登入後臺管理後,預設沒有我們建立的應用中定義的模型類,需要在自己應用中的admin.py檔案中註冊,才可以在後臺管理中看到,並進行增刪改查操作
自定義管理頁面
Django提供了自定義管理頁面的功能,比如列表頁要顯示哪些值
- /admin.py檔案程式碼如下
1 from django.contrib import admin 2 from booktest.models import BookInfo,HeroInfo 3 4 class BookInfoAdmin(admin.ModelAdmin): 5 list_display = [`id`, `btitle`, `bpub_date`] 6 class HeroInfoAdmin(admin.ModelAdmin): 7 list_display = [`id`, `hname`,`hgender`,`hcomment`] 8 9 admin.site.register(BookInfo,BookInfoAdmin) 10 admin.site.register(HeroInfo,HeroInfoAdmin)
模型
資料庫連線
/settings.py檔案,找到DATABASES項,預設使用SQLite3資料庫
修改為使用MySQL資料庫,程式碼如下:
將引擎改為mysql,提供連線的主機HOST、埠PORT、資料庫名NAME、使用者名稱USER、密碼PASSWORD。
DATABASES = { `default`: { `ENGINE`: `django.db.backends.mysql`, `NAME`: `test2`, #資料庫名字, `USER`: `root`, #資料庫登入使用者名稱 `PASSWORD`: `mysql`, #資料庫登入密碼 `HOST`: `localhost`, #資料庫所在主機 `PORT`: `3306`, #資料庫埠 } }
注意:資料庫test2 Django框架不會自動生成,需要我們自己進入mysql資料庫去建立
模型類
欄位型別
使用時需要引入django.db.models包,欄位型別如下:
AutoField:自動增長的IntegerField,通常不用指定,不指定時Django會自動建立屬性名為id的自動增長屬性。 BooleanField:布林欄位,值為True或False。 NullBooleanField:支援Null、True、False三種值。 CharField(max_length=字元長度):字串。 引數max_length表示最大字元個數。 TextField:大文字欄位,一般超過4000個字元時使用。 IntegerField:整數。 DecimalField(max_digits=None, decimal_places=None):十進位制浮點數。 引數max_digits表示總位數。 引數decimal_places表示小數位數。 FloatField:浮點數。 DateField[auto_now=False, auto_now_add=False]):日期。 引數auto_now表示每次儲存物件時,自動設定該欄位為當前時間,用於"最後一次修改"的時間戳,它總是使用當前日期,預設為false。 引數auto_now_add表示當物件第一次被建立時自動設定當前時間,用於建立的時間戳,它總是使用當前日期,預設為false。 引數auto_now_add和auto_now是相互排斥的,組合將會發生錯誤。 TimeField:時間,引數同DateField。 DateTimeField:日期時間,引數同DateField。 FileField:上傳檔案欄位。 ImageField:繼承於FileField,對上傳的內容進行校驗,確保是有效的圖片。
選項
通過選項實現對欄位的約束,選項如下:
null:如果為True,表示允許為空,預設值是False。 blank:如果為True,則該欄位允許為空白,預設值是False。 對比:null是資料庫範疇的概念,blank是表單驗證範疇的。 db_column:欄位的名稱,如果未指定,則使用屬性的名稱。 db_index:若值為True, 則在表中會為此欄位建立索引,預設值是False。 default:預設值。 primary_key:若為True,則該欄位會成為模型的主鍵欄位,預設值是False,一般作為AutoField的選項使用。 unique:如果為True, 這個欄位在表中必須有唯一值,預設值是False。
條件查詢
條件運算子
查詢等
1 list=BookInfo.objects.filter(id__exact=1) 2 可簡寫為: 3 list=BookInfo.objects.filter(id=1)
模糊查詢
說明:如果要包含%無需轉義,直接寫即可
- contains:是否包含
list = BookInfo.objects.filter(btitle__contains=`傳`)
- startswith、endswith:以指定值開頭或結尾
1 list = BookInfo.objects.filter(btitle__endswith=`部`)
以上運算子都區分大小寫,在這些運算子前加上i表示不區分大小寫,如iexact、icontains、istartswith、iendswith
空查詢
- isnull:是否為null
list = BookInfo.objects.filter(btitle__isnull=False)
範圍查詢
- in:是否包含在範圍內
1 list = BookInfo.objects.filter(id__in=[1, 3, 5])
比較查詢
- gt、gte、lt、lte:大於、大於等於、小於、小於等於
list = BookInfo.objects.filter(id__gt=3)
- 不等於的運算子,使用exclude()過濾器
1 list = BookInfo.objects.exclude(id=3)
日期查詢
- year、month、day、week_day、hour、minute、second:對日期時間型別的屬性進行運算
list = BookInfo.objects.filter(bpub_date__year=1980)
list = BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))
F物件
兩個屬性比較使用F物件
1 list = BookInfo.objects.filter(bread__gte=F(`bcomment`)) 2 list = BookInfo.objects.filter(bread__gt=F(`bcomment`) * 2)
Q物件
多個過濾器逐個呼叫表示邏輯與關係,同sql語句中where部分的and關鍵字
1 list=BookInfo.objects.filter(bread__gt=20,id__lt=3) 2 或 3 list=BookInfo.objects.filter(bread__gt=20).filter(id__lt=3) 4 5 list = BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3)) 6 7 Q物件前可以使用~操作符,表示非not 8 list = BookInfo.objects.filter(~Q(pk=3))
聚合函式
使用aggregate()過濾器呼叫聚合函式。聚合函式包括:Avg,Count,Max,Min,Sum,被定義在django.db.models中
list = BookInfo.objects.aggregate(Sum(`bread`))
注意aggregate的返回值是一個字典型別,格式如下:
{`聚合類小寫__屬性名`:值}
如:{`sum__bread`:3}
使用count時一般不使用aggregate()過濾器,count函式的返回值是一個數字
list = BookInfo.objects.count()
查詢集
返回查詢集的過濾器
all():返回所有資料。 filter():返回滿足條件的資料。 exclude():返回滿足條件之外的資料,相當於sql語句中where部分的not關鍵字。 order_by():對結果進行排序
返回單個值的過濾器
get():返回單個滿足條件的物件 如果未找到會引發"模型類.DoesNotExist"異常。 如果多條被返回,會引發"模型類.MultipleObjectsReturned"異常。 count():返回當前查詢結果的總條數。 aggregate():聚合,返回一個字典。
判斷某一個查詢集中是否有資料
exists():判斷查詢集中是否有資料,如果有則返回True,沒有則返回False
兩大特性
惰性執行:建立查詢集不會訪問資料庫,直到呼叫資料時,才會訪問資料庫,呼叫資料的情況包括迭代、序列化、與if合用。
快取:使用同一個查詢集,第一次使用時會發生資料庫的查詢,然後把結果快取下來,再次使用這個查詢集時會使用快取的資料
查詢集的快取
每個查詢集都包含一個快取來最小化對資料庫的訪問。
在新建的查詢集中,快取為空,首次對查詢集求值時,會發生資料庫查詢,django會將查詢的結果存在查詢集的快取中,並返回請求的結果,接下來對查詢集求值將重用快取中的結果。
限制查詢集
可以對查詢集進行取下標或切片操作,等同於sql中的limit和offset子句。 注意:不支援負數索引。 對查詢集進行切片後返回一個新的查詢集,不會立即執行查詢。 如果獲取一個物件,直接使用[0],等同於[0:1].get(),但是如果沒有資料,[0]引發IndexError異常,[0:1].get()如果沒有資料引發DoesNotExist異常。 示例:獲取第1、2項,執行檢視。 list=BookInfo.objects.all()[0:2]
模型類擴充套件
元選項
#定義圖書模型類BookInfo class BookInfo(models.Model): ... #定義元選項 class Meta: db_table=`bookinfo` #指定BookInfo生成的資料表名為bookinfo
檢視
URLconf
位置引數
1 url(r`^delete(d+)/$`,views.show_arg) 2 def show_arg(request,id): 3 return HttpResponse(`show arg %s`%id)
關鍵字引數
1 url(r`^delete(?P<id1>d+)/$`,views.show_arg) 2 def show_arg(request,id1): 3 return HttpResponse(`show %s`%id1)
HttpRequest物件
屬性
下面除非特別說明,屬性都是隻讀的
path:一個字串,表示請求的頁面的完整路徑,不包含域名和引數部分。 method:一個字串,表示請求使用的HTTP方法,常用值包括:`GET`、`POST`。 在瀏覽器中給出地址發出請求採用get方式,如超連結。 在瀏覽器中點選表單的提交按鈕發起請求,如果表單的method設定為post則為post請求。 encoding:一個字串,表示提交的資料的編碼方式。 如果為None則表示使用瀏覽器的預設設定,一般為utf-8。 這個屬性是可寫的,可以通過修改它來修改訪問表單資料使用的編碼,接下來對屬性的任何訪問將使用新的encoding值。 GET:QueryDict型別物件,類似於字典,包含get請求方式的所有引數。 POST:QueryDict型別物件,類似於字典,包含post請求方式的所有引數。 FILES:一個類似於字典的物件,包含所有的上傳檔案。 COOKIES:一個標準的Python字典,包含所有的cookie,鍵和值都為字串。 session:一個既可讀又可寫的類似於字典的物件,表示當前的會話,只有當Django 啟用會話的支援時才可用,詳細內容見"狀態保持"。
HttpResponse物件
屬性
content:表示返回的內容。 charset:表示response採用的編碼字符集,預設為utf-8。 status_code:返回的HTTP響應狀態碼。 content-type:指定返回資料的的MIME型別,預設為`text/html`。
方法
_init_:建立HttpResponse物件後完成返回內容的初始化。 set_cookie:設定Cookie資訊。 set_cookie(key, value=``, max_age=None, expires=None) cookie是網站以鍵值對格式儲存在瀏覽器中的一段純文字資訊,用於實現使用者跟蹤。 max_age是一個整數,表示在指定秒數後過期。 expires是一個datetime或timedelta物件,會話將在這個指定的日期/時間過期。 max_age與expires二選一。 如果不指定過期時間,在關閉瀏覽器時cookie會過期。 delete_cookie(key):刪除指定的key的Cookie,如果key不存在則什麼也不發生。 write:向響應體中寫資料。
狀態保持
- 瀏覽器請求伺服器是無狀態的。
- 無狀態指一次使用者請求時,瀏覽器、伺服器無法知道之前這個使用者做過什麼,每次請求都是一次新的請求。
- 無狀態的應用層面的原因是:瀏覽器和伺服器之間的通訊都遵守HTTP協議。
- 根本原因是:瀏覽器與伺服器是使用Socket套接字進行通訊的,伺服器將請求結果返回給瀏覽器之後,會關閉當前的Socket連線,而且伺服器也會在處理頁面完畢之後銷燬頁面物件
有時需要儲存下來使用者瀏覽的狀態,比如使用者是否登入過,瀏覽過哪些商品等。 實現狀態保持主要有兩種方式
- 在客戶端儲存資訊使用Cookie
- 在伺服器端儲存資訊使用Session
狀態保持
Cookie
- 指某些網站為了辨別使用者身份、進行session跟蹤而儲存在使用者本地終端上的資料(通常經過加密)
- Cookie是由伺服器端生成,傳送給User-Agent(一般是瀏覽器),瀏覽器會將Cookie的key/value儲存到某個目錄下的文字檔案內,下次請求同一網站時就傳送該Cookie給伺服器(前提是瀏覽器設定為啟用cookie)
- Cookie名稱和值可以由伺服器端開發自己定義,這樣伺服器可以知道該使用者是否是合法使用者以及是否需要重新登入等
- 伺服器可以利用Cookies包含資訊的任意性來篩選並經常性維護這些資訊,以判斷在HTTP傳輸中的狀態。Cookies最典型記住使用者名稱
Cookie的特點
- Cookie以鍵值對的格式進行資訊的儲存
- Cookie基於域名安全,不同域名的Cookie是不能互相訪問的
- 當瀏覽器請求某網站時,會將瀏覽器儲存的跟網站相關的所有Cookie資訊提交給網站伺服器
設定Cookie
response.set_cookie(`h1`, `你好`)
讀取Cookie
response.write(`<h1>` + request.COOKIES[`h1`] + `</h1>`)
Session
在伺服器端進行狀態保持的方案就是Session
啟用Session
Django專案預設啟用Session
- /settings.py檔案,在項MIDDLEWARE_CLASSES中啟用Session中介軟體
儲存方式
/settings.py檔案,設定SESSION_ENGINE項指定Session資料儲存的方式,可以儲存在資料庫、快取、Redis等
- 儲存在資料庫中,如下設定可以寫,也可以不寫,這是預設儲存方式
SESSION_ENGINE=`django.contrib.sessions.backends.db`
- 儲存在快取中:儲存在本機記憶體中,如果丟失則不能找回,比資料庫的方式讀寫更快
SESSION_ENGINE=`django.contrib.sessions.backends.cache`
- 混合儲存:優先從本機記憶體中存取,如果沒有則從資料庫中存取
SESSION_ENGINE=`django.contrib.sessions.backends.cached_db`
- 如果儲存在資料庫中,需要在項INSTALLED_APPS中安裝Session應用
- 遷移後會在資料庫中建立出儲存Session的表
- 由表結構可知,操作Session包括三個資料:鍵,值,過期時間
依賴於Cookie
所有請求者的Session都會儲存在伺服器中,伺服器如何區分請求者和Session資料的對應關係呢?
-
在使用Session後,會在Cookie中儲存一個sessionid的資料,每次請求時瀏覽器都會將這個資料發給伺服器,伺服器在接收到sessionid後,會根據這個值找出這個請求者的Session
-
結果:如果想使用Session,瀏覽器必須支援Cookie,否則就無法使用Session了
-
儲存Session時,鍵與Cookie中的sessionid相同,值是開發人員設定的鍵值對資訊,進行了base64編碼,過期時間由開發人員設定
物件及方法
通過HttpRequest物件的session屬性進行會話的讀寫操作
- 以鍵值對的格式寫session
request.session[`鍵`]=值
- 根據鍵讀取值
request.session.get(`鍵`,預設值)
- 清除所有session,在儲存中刪除值部分
request.session.clear()
- 清除session資料,在儲存中刪除session的整條資料
request.session.flush()
- 刪除session中的指定鍵及值,在儲存中只刪除某個鍵及對應的值
del request.session[`鍵`]
- 設定會話的超時時間,如果沒有指定過期時間則兩個星期後過期
設定會話的超時時間,如果沒有指定過期時間則兩個星期後過期
- value
- 如果value是一個整數,會話將在value秒沒有活動後過期
- 如果value為0,那麼使用者會話的Cookie將在使用者的瀏覽器關閉時過期
- 如果value為None,那麼會話永不過期
使用Redis儲存Session
會話還支援檔案、純cookie、Memcached、Redis等方式儲存
- 安裝包
pip install django-redis-sessions==0.5.6
- /settings檔案,增加如下項:
SESSION_ENGINE = `redis_sessions.session` SESSION_REDIS_HOST = `localhost` SESSION_REDIS_PORT = 6379 SESSION_REDIS_DB = 2 SESSION_REDIS_PASSWORD = `` SESSION_REDIS_PREFIX = `session`
模板
模板語言
標籤
-
for標籤語法如下: {%for item in 列表%} 迴圈邏輯 {{forloop.counter}}表示當前是第幾次迴圈,從1開始 {%empty%} 列表為空或不存在時執行此邏輯 {%endfor%} if標籤語法如下: {%if ...%} 邏輯1 {%elif ...%} 邏輯2 {%else%} 邏輯3 {%endif%}
過濾器
變數|過濾器:引數
- 長度length,返回字串包含字元的個數,或列表、元組、字典的元素個數
- 預設值default,如果變數不存在時則返回預設值
data|default:`預設值`
日期date,用於對日期型別的值進行字串格式化,常用的格式化字元如下:
Y表示年,格式為4位,y表示兩位的年。 m表示月,格式為01,02,12等。 d表示日, 格式為01,02等。 j表示日,格式為1,2等。 H表示時,24進位制,h表示12進位制的時。 i表示分,為0-59。 s表示秒,為0-59。 value|date:"Y年m月j日 H時i分s秒"
HTML轉義
關閉轉義
過濾器escape可以實現對變數的html轉義,預設模板就會轉義,一般省略
{{t1|escape}}
過濾器safe:禁用轉義,告訴模板這個變數是安全的,可以解釋執行
{{data|safe}}
標籤autoescape:設定一段程式碼都禁用轉義,接受on、off引數
{%autoescape off%}
...
{%endautoescape%}
CSRF
CSRF全拼為Cross Site Request Forgery,譯為跨站請求偽造。CSRF指攻擊者盜用了你的身份,以你的名義傳送惡意請求
驗證碼
手動實現驗證碼
- /views.py檔案中,建立檢視verify_code
- 隨機生成字串後存入session中,用於後續判斷
- 檢視返回mime-type為image/png
1 from PIL import Image, ImageDraw, ImageFont 2 from django.utils.six import BytesIO 3 ... 4 def verify_code(request): 5 #引入隨機函式模組 6 import random 7 #定義變數,用於畫面的背景色、寬、高 8 bgcolor = (random.randrange(20, 100), random.randrange( 9 20, 100), 255) 10 width = 100 11 height = 25 12 #建立畫面物件 13 im = Image.new(`RGB`, (width, height), bgcolor) 14 #建立畫筆物件 15 draw = ImageDraw.Draw(im) 16 #呼叫畫筆的point()函式繪製噪點 17 for i in range(0, 100): 18 xy = (random.randrange(0, width), random.randrange(0, height)) 19 fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) 20 draw.point(xy, fill=fill) 21 #定義驗證碼的備選值 22 str1 = `ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0` 23 #隨機選取4個值作為驗證碼 24 rand_str = `` 25 for i in range(0, 4): 26 rand_str += str1[random.randrange(0, len(str1))] 27 #構造字型物件,ubuntu的字型路徑為“/usr/share/fonts/truetype/freefont” 28 font = ImageFont.truetype(`FreeMono.ttf`, 23) 29 #構造字型顏色 30 fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255)) 31 #繪製4個字 32 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor) 33 draw.text((25, 2), rand_str[1], font=font, fill=fontcolor) 34 draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) 35 draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) 36 #釋放畫筆 37 del draw 38 #存入session,用於做進一步驗證 39 request.session[`verifycode`] = rand_str 40 #記憶體檔案操作 41 buf = BytesIO() 42 #將圖片儲存在記憶體中,檔案型別為png 43 im.save(buf, `png`) 44 #將記憶體中的圖片資料返回給客戶端,MIME型別為圖片png 45 return HttpResponse(buf.getvalue(), `image/png`)
驗證
- /views.py檔案中,建立檢視verify_yz
1 def verify_yz(request): 2 yzm=request.POST.get(`yzm`) 3 verifycode=request.session[`verifycode`] 4 response=HttpResponse(`no`) 5 if yzm==verifycode: 6 response=HttpResponse(`ok`) 7 return response
換驗證碼
<script type="text/javascript" src="/static/jquery-1.12.4.min.js"></script> <script type="text/javascript"> $(function(){ $(`#change`).css(`cursor`,`pointer`).click(function() { $(`#yzm`).attr(`src`,$(`#yzm`).attr(`src`)+1) }); }); </script> ... <img id="yzm" src="/verify_code/?1"/> <span id="change">看不清,換一個</span>
反向解析
在定義url時,需要為include定義namespace屬性,為url定義name屬性,使用時,在模板中使用url標籤,在檢視中使用reverse函式,根據正規表示式動態生成地址,減輕後期維護成本
url(r`^`,include(`booktest.urls`,namespace=`booktest`)) url(r`^fan2/$`, views.fan2,name=`fan2`) 反向解析:<a href="{%url `booktest:fan2`%}">fan2</a> return redirect(reverse(`booktest:fan2`))
常用
靜態檔案處理
- /settings.py檔案中定義靜態檔案存放的物理目錄
STATIC_URL = `/static/` STATICFILES_DIRS = [ os.path.join(BASE_DIR, `static`), ]
分頁
Paginator類例項物件
方法_init_(列表,int):返回分頁物件,第一個引數為列表資料,第二個引數為每頁資料的條數。 屬性count:返回物件總數。 屬性num_pages:返回頁面總數。 屬性page_range:返回頁碼列表,從1開始,例如[1, 2, 3, 4]。 方法page(m):返回Page類例項物件,表示第m頁的資料,下標以1開始
Page類例項物件
呼叫Paginator物件的page()方法返回Page物件,不需要手動構造。 屬性object_list:返回當前頁物件的列表。 屬性number:返回當前是第幾頁,從1開始。 屬性paginator:當前頁對應的Paginator物件。 方法has_next():如果有下一頁返回True。 方法has_previous():如果有上一頁返回True。 方法len():返回當前頁面物件的個數。
示例
- /views.py檔案中建立檢視page_test
1 from django.core.paginator import Paginator 2 from booktest.models import AreaInfo 3 ... 4 #引數pIndex表示:當前要顯示的頁碼 5 def page_test(request,pIndex): 6 #查詢所有的地區資訊 7 list1 = AreaInfo.objects.filter(aParent__isnull=True) 8 #將地區資訊按一頁10條進行分頁 9 p = Paginator(list1, 10) 10 #如果當前沒有傳遞頁碼資訊,則認為是第一頁,這樣寫是為了請求第一頁時可以不寫頁碼 11 if pIndex == ``: 12 pIndex = `1` 13 #通過url匹配的引數都是字串型別,轉換成int型別 14 pIndex = int(pIndex) 15 #獲取第pIndex頁的資料 16 list2 = p.page(pIndex) 17 #獲取所有的頁碼資訊 18 plist = p.page_range 19 #將當前頁碼、當前頁的資料、頁碼資訊傳遞到模板中 20 return render(request, `booktest/page_test.html`, {`list`: list2, `plist`: plist, `pIndex`: pIndex})
- /urls.py檔案中配置url
url(r`^page(?P<pIndex>[0-9]*)/$`, views.page_test)
- 建立page_test.html模板檔案
<html> <head> <title>分頁</title> </head> <body> 顯示當前頁的地區資訊:<br> <ul> {%for area in list%} <li>{{area.id}}--{{area.atitle}}</li> {%endfor%} </ul> <hr> 顯示頁碼資訊:當前頁碼沒有連結,其它頁碼有連結<br> {%for pindex in plist%} {%if pIndex == pindex%} {{pindex}} {%else%} <a href="/page{{pindex}}/">{{pindex}}</a> {%endif%} {%endfor%} </body> </html>
示例:省市區選擇
1 <html> 2 <head> 3 <title>省市區列表</title> 4 <script type="text/javascript" src="/static/js/jquery-1.12.4.min.js"></script> 5 <script type="text/javascript"> 6 $(function(){ 7 //頁面載入完成後獲取省資訊,並新增到省select 8 $.get(`/area2/`,function(dic) { 9 pro=$(`#pro`) 10 $.each(dic.data,function(index,item){ 11 pro.append(`<option value=`+item[0]+`>`+item[1]+`</option>`); 12 }) 13 }); 14 //為省select繫結change事件,獲取市資訊,並新增到市select 15 $(`#pro`).change(function(){ 16 $.get(`/area3_`+$(this).val()+`/`,function(dic){ 17 city=$(`#city`); 18 city.empty().append(`<option value="">請選擇市</option>`); 19 dis=$(`#dis`); 20 dis.empty().append(`<option value="">請選擇區縣</option>`); 21 $.each(dic.data,function(index,item){ 22 city.append(`<option value=`+item[0]+`>`+item[1]+`</option>`); 23 }) 24 }); 25 }); 26 //為市select繫結change事件,獲取區縣資訊,並新增到區縣select 27 $(`#city`).change(function(){ 28 $.get(`/area3_`+$(this).val()+`/`,function(dic){ 29 dis=$(`#dis`); 30 dis.empty().append(`<option value="">請選擇區縣</option>`); 31 $.each(dic.data,function(index,item){ 32 dis.append(`<option value=`+item[0]+`>`+item[1]+`</option>`); 33 }) 34 }) 35 }); 36 37 }); 38 </script> 39 </head> 40 <body> 41 <select id="pro"> 42 <option value="">請選擇省</option> 43 </select> 44 <select id="city"> 45 <option value="">請選擇市</option> 46 </select> 47 <select id="dis"> 48 <option value="">請選擇區縣</option> 49 </select> 50 </body> 51 </html
celery
情景:使用者發起request,並等待response返回。在本些views中,可能需要執行一段耗時的程式,那麼使用者就會等待很長時間,造成不好的使用者體驗,比如傳送郵件、手機驗證碼等
celery名詞
- 任務task:就是一個Python函式
- 佇列queue:將需要執行的任務加入到佇列中
- 工人worker:在一個新程式中,負責執行佇列中的任務
- 代理人broker:負責排程,在佈置環境中使用redis
- /settings.py中安裝
INSTALLED_APPS = ( ... `djcelery`, }
- /settings.py檔案中配置代理和任務模組
import djcelery djcelery.setup_loader() BROKER_URL = `redis://127.0.0.1:6379/2`
- 建立tasks.py檔案
1 import time 2 from celery import task 3 4 @task 5 def sayhello(): 6 print(`hello ...`) 7 time.sleep(2) 8 print(`world ...`)
- /views.py檔案,修改sayhello檢視
1 from booktest import tasks 2 ... 3 def sayhello(request): 4 # print(`hello ...`) 5 # time.sleep(2) 6 # print(`world ...`) 7 tasks.sayhello.delay() 8 return HttpResponse("hello world")
- 執行遷移生成celery需要的資料表
python manage.py migrate
- 啟動Redis,如果已經啟動則不需要啟動
sudo service redis start
- 啟動worker
python manage.py celery worker --loglevel=info
- 修改為傳送郵件的程式碼,就可以實現無阻塞傳送郵件
1 from django.conf import settings 2 from django.core.mail import send_mail 3 from celery import task 4 5 @task 6 def sayhello(): 7 msg=`<a href="http://www.itcast.cn/subject/pythonzly/index.shtml" target="_blank">點選啟用</a>` 8 send_mail(`註冊啟用`,``,settings.EMAIL_FROM, 9 [`itcast88@163.com`], 10 html_message=msg)
請使用手機”掃一掃”x