一、目的&環境準備javascript
目的把分頁寫成一個模塊的方式而後在須要分頁的地方直接調用模塊就好了。html
環境準備Django中生成一個APP而且註冊,配置URL&Views前端
配置URLjava
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^user_list/',views.user_list), ]
註冊APPpython
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ]
配置modelsweb
from __future__ import unicode_literals from django.db import models # Create your models here. class UserList(models.Model): username = models.CharField(max_length=32) age = models.IntegerField()
二、分析數據庫
分頁在基本上行全部的大型網站中都是須要的,好比博客園的分頁,當咱們查詢的時候或查看的時候他有不少博文,難道他是一下把全部的博文都給咱們返回的嗎?固然不是:以下圖django
咱們能夠根據提示來點擊上一頁和下一頁或者點擊咱們想要查看的頁面,而後顯示咱們要查看的博文連接!而不是一下把全部的博文給顯示出來,這樣即節省流量又能改善用戶體驗。後端
三、逐步完善分頁代碼瀏覽器
首先我們先建立500條數據(以前不要忘記生成數據庫),在第一訪問時設置下就OK
3.一、配置views建立數據
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here. def user_list(request): for i in range(500): dic = {'username': 'name_%d' % i, 'age': i} models.UserList.objects.create(**dic) return HttpResponse('OK')
3.二、配置html顯示數據並經過views獲取數據顯示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> {% for line in result %} <tr> <td>{{ line.username }}</td> <td>{{ line.age }}</td> </tr> {% endfor %} </table> <div> {{ pager_str|safe }} </div> </body> </html>
views
def user_list(request): result = models.UserList.objects.all() return render(request,'user_list.html',{'result':result})
這樣,前端能夠正常顯示我們去的數據了,可是一會兒把全部的數據都取出來了。不是我們想要的結果。
3.三、取指定的條數
好比我想取前10條怎麼取呢?
def user_list(request): result = models.UserList.objects.all()[0:10] return render(request,'user_list.html',{'result':result})
那我讓[0:10]動態起來就能夠了!開始和結尾。
3.四、每頁顯示10條數據
向用戶獲取頁數,咱們能夠配置URL在URL中有兩種方式查詢直接在URL中配置正則,而後在views裏能夠經過參數來獲取用戶傳過來的值,
也能夠經過?a=9 &b=10 這樣在Veiws函數裏能夠經過request.GET['a']取值了,而且能夠設置默認值request.GET.get('a',0)
def user_list(request): current_page = request.GET.get('page') print current_page result = models.UserList.objects.all()[0:10] return render(request,'user_list.html',{'result':result})
測試:
這裏的問號是經過get的方式向後端發送數據,咱們也能夠修改form表單中method改成GET,那麼數據訪問的時候就是經過GET方式向後端提交數據的,當點擊form表單提交數據的時候,form裏的內容會自動添加到瀏覽器的URL中以上面的格式!
雖然POST和GET均可以向後端提交數據可是規定:GET通常用來查詢使用,POST通常用來提交修改數據使用,根據實際的狀況來定!
看下面的代碼:
def user_list(request): current_page = request.GET.get('page',1) print current_page start = 0 #10 20 (current_page-1)*10 end = 10 #20 30 current_page*10 result = models.UserList.objects.all()[start:end] return render(request,'user_list.html',{'result':result})
咱們如今讓start & end 動態起來頁面動態起來是否是就更好了?
def user_list(request): current_page = request.GET.get('page',1) current_page = int(current_page) start = (current_page-1)*10 #10 20 (current_page-1)*10 end = current_page*10 #20 30 current_page*10 result = models.UserList.objects.all()[start:end] return render(request,'user_list.html',{'result':result})
而後打開網頁測試下,修改page的值來看下顯示效果:
http://127.0.0.1:8000/user_list/?page=2
http://127.0.0.1:8000/user_list/?page=3
http://127.0.0.1:8000/user_list/?page=4
咱們經過把上面的代碼整理一下整理到函數或類裏下次使用的時候直接調用類或者函數便可。
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here. class Pager(object): def __init__(self,current_page): self.current_page = int(current_page) #把方法僞形成屬性(1) @property def start(self): return (self.current_page-1)*10 @property def end(self): return self.current_page*10 def user_list(request): current_page = request.GET.get('page',1) page_obj = Pager(current_page) #把方法改形成屬性(2),這樣在下面調用方法的時候就不須要加括號了 result = models.UserList.objects.all()[page_obj.start:page_obj.end] return render(request,'user_list.html',{'result':result})
二、生成按鈕頁
上面的功能實現了分頁如今,咱們是否是能夠在下面生成一堆的按鈕來讓用戶點擊,而不是在瀏覽器中輸入!
先看下若是我們手動寫的話!
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> {% for line in result %} <tr> <td>{{ line.username }}</td> <td>{{ line.age }}</td> </tr> {% endfor %} </table> <div> <a href="/user_list/?page=1">1</a> <a href="/user_list/?page=2">2</a> <a href="/user_list/?page=3">3</a> <a href="/user_list/?page=4">4</a> <a href="/user_list/?page=5">5</a> </div> </body> </html>
以下圖:
目的是爲了實現左側的效果,可是我們不可能手寫吧?因此應該在後臺建立,這個是否是就是總共有多少頁?
需求分析:
每頁顯示10條數據
共500條數據就是50頁,那有501條數據呢?是多少頁是51頁。
能夠經過divmod(500,10),他會的到一個元組,第一個值是值,第二個值是餘數,咱們就經過判斷他是否有餘數來判斷是不是整頁,若是有餘數在整頁基礎加1便可!
咱們獲取了全部的頁數以後能夠吧他返回在前端生成,可是這樣咱們後端作了分頁以後前端是否是也作了分頁操做?
咱們能夠在後端生成一個大字符串而後把他返回給前端(拼接的URL)
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here. class Pager(object): def __init__(self,current_page): self.current_page = int(current_page) #把方法僞形成屬性(1) @property def start(self): return (self.current_page-1)*10 @property def end(self): return self.current_page*10 def user_list(request): current_page = request.GET.get('page',1) page_obj = Pager(current_page) #吧方法未形成屬性(2),這樣在下面調用方法的時候就不須要加括號了 result = models.UserList.objects.all()[page_obj.start:page_obj.end] all_item = models.UserList.objects.all().count() all_page,div = divmod(all_item,10) if div > 0: all_page +=1 pager_str = "" for i in range(1,all_page+1): #每次循環生成一個標籤 temp = '<a href="/user_list/?page=%d">%d</a>' %(i,i,) #把標籤拼接而後返回給前端 pager_str += temp return render(request,'user_list.html',{'result':result,'pager_str':pager_str})
前端配置:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> {% for line in result %} <tr> <td>{{ line.username }}</td> <td>{{ line.age }}</td> </tr> {% endfor %} </table> <div> {{ pager_str }} </div> </body> </html>
可是有個問題以下圖:
這個是什麼問題致使的呢?
我們在以前的文章學過一個CSRF跨站請求僞造的安全設置,這裏還有一個值得說的安全就是XSS攻擊:
XSS攻擊:跨站腳本攻擊(Cross Site Scripting),爲不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫爲XSS。
XSS是一種常常出如今web應用中的計算機安全漏洞,它容許惡意web用戶將代碼植入到提供給其它用戶使用的頁面中。好比這些代碼包括HTML代碼和客戶端腳本。攻擊者利用XSS漏洞旁路掉訪問控制——例如同源策略(same origin policy)。這種類型的漏洞因爲被黑客用來編寫危害性更大的網絡釣魚(Phishing)攻擊而變得廣爲人知。對於跨站腳本攻擊,黑客界共識是:跨站腳本攻擊是新型的「緩衝區溢出攻擊「,而JavaScript是新型的「ShellCode」。
我們上面看到的內容就是Django爲了防止這樣的狀況產生而設置的機制,例子以下:
若是,寫的簡單的script能夠被保存爲HTML標籤的話那麼?只要有人打開這個頁面都會提示一個信息,這樣是否是不安全,這個是小的說的!
若是說這裏是一個獲取Cookie而後發送到指定服務器而後服務器能夠經過cookie訪問你的我的信息是否是就可怕了?!
那麼怎麼解決這個問題呢?能夠經過模板語言的一個函數來告訴Django這個是安全的:加一個safe (在文章的後面還有一種方法在後端標記他是安全的)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> {% for line in result %} <tr> <td>{{ line.username }}</td> <td>{{ line.age }}</td> </tr> {% endfor %} </table> <div> {{ pager_str|safe }} </div> </body> </html>
效果以下:
這樣全顯示出來了,不是很好,最好顯示11頁而後,當用戶點擊第6頁的時候,這個6永遠在中間!因此咱們也要讓頁碼動態起來!
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here. class Pager(object): def __init__(self,current_page): self.current_page = int(current_page) #把方法僞形成屬性(1) @property def start(self): return (self.current_page-1)*10 @property def end(self): return self.current_page*10 def page_str(self,all_item,base_url): all_page, div = divmod(all_item, 10) if div > 0: all_page += 1 pager_str = "" #默承認以看到的頁碼11個 start = self.current_page - 5 end = self.current_page + 6 #把頁面動態起來傳入起始和結束 for i in range(start, end): #判斷是否爲當前頁 if i == self.current_page: temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) else: temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) # 把標籤拼接而後返回給前端 pager_str += temp return pager_str def user_list(request): current_page = request.GET.get('page',1) page_obj = Pager(current_page) #吧方法未形成屬性(2),這樣在下面調用方法的時候就不須要加括號了 result = models.UserList.objects.all()[page_obj.start:page_obj.end] all_item = models.UserList.objects.all().count() pager_str = page_obj.page_str(all_item,'/user_list/') return render(request,'user_list.html',{'result':result,'pager_str':pager_str})
前端頁面不用修改了,看效果以下:
如今仍是有問題的,當你如今點擊1,2,3,4,5的時候由於前面沒有頁面就會出現負值!
而且最後一頁頁會出現無窮大,可是沒有數據,那怎麼解決呢?
''' 若是總頁數 <= 11 好比9頁: 那麼,還有必要讓頁碼動起來嗎?就不必了直接顯示總共頁數就好了!start就是1,end就是9就好了 else: 若是當前頁小宇6: start:1 end:11 若是當前頁大於6: start:當前頁-5 end:當前頁+6 若是當前頁+6 >總頁數: start:總頁數-10 end:總頁數 '''
修改後的代碼:
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here. class Pager(object): def __init__(self,current_page): self.current_page = int(current_page) #把方法僞形成屬性(1) @property def start(self): return (self.current_page-1)*10 @property def end(self): return self.current_page*10 def page_str(self,all_item,base_url): all_page, div = divmod(all_item, 10) if div > 0: all_page += 1 pager_str = "" # #默承認以看到的頁碼11個 # # start = self.current_page - 5 # end = self.current_page + 6 # # #把頁面動態起來傳入起始和結束 # for i in range(start, end): # # #判斷是否爲當前頁 # if i == self.current_page: # temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) # else: # temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) # # # 把標籤拼接而後返回給前端 # pager_str += temp if all_page <= 11: start = 1 end = all_page else: if self.current_page <= 6: start = 1 end = 11 + 1 else: start = self.current_page - 5 end = self.current_page + 6 if self.current_page + 6 > all_page: start = all_page - 10 end = all_page + 1 #把頁面動態起來傳入起始和結束 for i in range(start, end): #判斷是否爲當前頁 if i == self.current_page: temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) else: temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) # 把標籤拼接而後返回給前端 pager_str += temp return pager_str def user_list(request): current_page = request.GET.get('page',1) page_obj = Pager(current_page) #把方法改形成屬性(2),這樣在下面調用方法的時候就不須要加括號了 result = models.UserList.objects.all()[page_obj.start:page_obj.end] all_item = models.UserList.objects.all().count() pager_str = page_obj.page_str(all_item,'/user_list/') return render(request,'user_list.html',{'result':result,'pager_str':pager_str})
這樣簡單分頁就完成了,如今咱們能夠在給他增長一個「上一頁」 & 下一頁
咱們能夠把他給爲一個列表,而後每次生成的標籤append到列表中,而後分別在列表中最前面和後面增長,上一頁和下一頁
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here. class Pager(object): def __init__(self,current_page): self.current_page = int(current_page) #把方法僞形成屬性(1) @property def start(self): return (self.current_page-1)*10 @property def end(self): return self.current_page*10 def page_str(self,all_item,base_url): all_page, div = divmod(all_item, 10) if div > 0: all_page += 1 pager_list = [] if all_page <= 11: start = 1 end = all_page else: if self.current_page <= 6: start = 1 end = 11 + 1 else: start = self.current_page - 5 end = self.current_page + 6 if self.current_page + 6 > all_page: start = all_page - 10 end = all_page + 1 #把頁面動態起來傳入起始和結束 for i in range(start, end): #判斷是否爲當前頁 if i == self.current_page: temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) else: temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) # 把標籤拼接而後返回給前端 pager_list.append(temp) #上一頁 if self.current_page > 1: pre_page = '<a href="%s?page=%d">上一頁</a>' % (base_url, self.current_page - 1) else: # javascript:void(0) 什麼都不幹 pre_page = '<a href="javascript:void(0);">上一頁</a>' #下一頁 if self.current_page >= all_page: next_page = '<a href="javascript:void(0);">下一頁</a>' else: next_page = '<a href="%s?page=%d">下一頁</a>' % (base_url, self.current_page + 1) pager_list.insert(0, pre_page) pager_list.append(next_page) return "".join(pager_list) def user_list(request): current_page = request.GET.get('page',1) page_obj = Pager(current_page) #把方法改形成屬性(2),這樣在下面調用方法的時候就不須要加括號了 result = models.UserList.objects.all()[page_obj.start:page_obj.end] all_item = models.UserList.objects.all().count() pager_str = page_obj.page_str(all_item,'/user_list/') return render(request,'user_list.html',{'result':result,'pager_str':pager_str})
最後寫成模塊,也能夠吧分頁的數量動態化!
前面說過關於XSS的問題,還有一種方式在後端告訴他是安全的便可,前端就不須要標記了。
導入並使用模塊便可:
#!/usr/bin/env python #-*- coding:utf-8 -*- from django.utils.safestring import mark_safe #把拼接的HTML標記爲安全的便可 return mark_safe("".join(pager_list))
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> {% for line in result %} <tr> <td>{{ line.username }}</td> <td>{{ line.age }}</td> </tr> {% endfor %} </table> <div> {{ pager_str }} </div> </body> </html>
#!/usr/bin/env python #-*- coding:utf-8 -*- from django.utils.safestring import mark_safe class Pager(object): def __init__(self,current_page): self.current_page = int(current_page) #把方法僞形成屬性(1) @property def start(self): return (self.current_page-1)*10 @property def end(self): return self.current_page*10 def page_str(self,all_item,base_url): all_page, div = divmod(all_item, 10) if div > 0: all_page += 1 pager_list = [] if all_page <= 11: start = 1 end = all_page else: if self.current_page <= 6: start = 1 end = 11 + 1 else: start = self.current_page - 5 end = self.current_page + 6 if self.current_page + 6 > all_page: start = all_page - 10 end = all_page + 1 #把頁面動態起來傳入起始和結束 for i in range(start, end): #判斷是否爲當前頁 if i == self.current_page: temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) else: temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i) # 把標籤拼接而後返回給前端 pager_list.append(temp) #上一頁 if self.current_page > 1: pre_page = '<a href="%s?page=%d">上一頁</a>' % (base_url, self.current_page - 1) else: # javascript:void(0) 什麼都不幹 pre_page = '<a href="javascript:void(0);">上一頁</a>' #下一頁 if self.current_page >= all_page: next_page = '<a href="javascript:void(0);">下一頁</a>' else: next_page = '<a href="%s?page=%d">下一頁</a>' % (base_url, self.current_page + 1) pager_list.insert(0, pre_page) pager_list.append(next_page) return mark_safe("".join(pager_list))