day18-2-django之分頁和session
Django-4
知識預覽
- 分頁器(paginator)
- COOKIE 與 SESSION
分頁器(paginator)
分頁器的使用
>>> from django.core.paginator
import
Paginator
>>> objects = [
‘john‘
,
‘paul‘
,
‘george‘
,
‘ringo‘
]
>>> p = Paginator(objects, 2)
>>> p.count
#數據總數
4
>>> p.num_pages
#總頁數
2
>>> type(p.page_range)
# `<type ‘rangeiterator‘>` in Python 2.
<
class
‘range_iterator‘
>
>>> p.page_range
#頁碼的列表
range(1, 3)
# =========[1,2]
>>> page1 = p.page(1)
#第1頁的page對象
>>> page1
<Page 1 of 2>
>>> page1.object_list
#第1頁的數據
[
‘john‘
,
‘paul‘
]
>>> page2 = p.page(2)
>>> page2.object_list
#第2頁的數據
[
‘george‘
,
‘ringo‘
]
>>> page2.has_next()
#是否有下一頁
False
>>> page2.has_previous()
#是否有上一頁
True
>>> page2.has_other_pages()
#是否有其他頁
True
>>> page2.next_page_number()
#下一頁的頁碼
Traceback (most recent call last):
...
EmptyPage: That page contains no results
>>> page2.previous_page_number()
#上一頁的頁碼
1
>>> page2.start_index()
# 本頁第一條記錄的序數(從1開始)
3
>>> page2.end_index()
# 本頁最後錄一條記錄的序數(從1開始)
4
>>> p.page(0)
#錯誤的頁,拋出異常
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1
>>> p.page(3)
#錯誤的頁,拋出異常
Traceback (most recent call last):
...
EmptyPage: That page contains no results
實現一個分頁效果:
Template:
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{% static ‘bootstrap.css‘ %}"> </head> <body> <div class="container"> <h4>分頁器</h4> <ul> {% for book in book_list %} <li>{{ book.title }} {{ book.price }}</li> {% endfor %} </ul> <ul class="pagination" id="pager"> {% if book_list.has_previous %} <li class="previous"><a href="/blog/?page={{ book_list.previous_page_number }}">上一頁</a></li> {% else %} <li class="previous disabled"><a href="#">上一頁</a></li> {% endif %} {% for num in paginator.page_range %} {% if num == currentPage %} <li class="item active"><a href="/blog/?page={{ num }}">{{ num }}</a></li> {% else %} <li class="item"><a href="/blog/?page={{ num }}">{{ num }}</a></li> {% endif %} {% endfor %} {% if book_list.has_next %} <li class="next"><a href="/blog/?page={{ book_list.next_page_number }}">下一頁</a></li> {% else %} <li class="next disabled"><a href="#">下一頁</a></li> {% endif %} </ul> </div> </body> </html>
views:
from django.shortcuts import render,HttpResponse # Create your views here. from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from app01.models import * def index(request): ‘‘‘ 批量導入數據: Booklist=[] for i in range(100): Booklist.append(Book(title="book"+str(i),price=30+i*i)) Book.objects.bulk_create(Booklist) ‘‘‘ book_list=Book.objects.all() paginator = Paginator(book_list, 10) page = request.GET.get(‘page‘,1) currentPage=int(page) try: print(page) book_list = paginator.page(page) except PageNotAnInteger: book_list = paginator.page(1) except EmptyPage: book_list = paginator.page(paginator.num_pages) return render(request,"index.html",locals())回到頂部
COOKIE 與 SESSION
簡介
1、cookie不屬於http協議範圍,由於http協議無法保持狀態,但實際情況,我們卻又需要“保持狀態”,因此cookie就是在這樣一個場景下誕生。
cookie的工作原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上cookie,這樣服務器就能通過cookie的內容來判斷這個是“誰”了。
2、cookie雖然在一定程度上解決了“保持狀態”的需求,但是由於cookie本身最大支持4096字節,以及cookie本身保存在客戶端,可能被攔截或竊取,因此就需要有一種新的東西,它能支持更多的字節,並且他保存在服務器,有較高的安全性。這就是session。
問題來了,基於http協議的無狀態特征,服務器根本就不知道訪問者是“誰”。那麽上述的cookie就起到橋接的作用。
我們可以給每個客戶端的cookie分配一個唯一的id,這樣用戶在訪問時,通過cookie,服務器就知道來的人是“誰”。然後我們再根據不同的cookie的id,在服務器上保存一段時間的私密資料,如“賬號密碼”等等。
3、總結而言:cookie彌補了http無狀態的不足,讓服務器知道來的人是“誰”;但是cookie以文本的形式保存在本地,自身安全性較差;所以我們就通過cookie識別不同的用戶,對應的在session裏保存私密的信息以及超過4096字節的文本。
4、另外,上述所說的cookie和session其實是共通性的東西,不限於語言和框架
認證應用
前幾節的介紹中我們已經有能力制作一個登陸頁面,在驗證了用戶名和密碼的正確性後跳轉到後臺的頁面。但是測試後也發現,如果繞過登陸頁面。直接輸入後臺的url地址也可以直接訪問的。這個顯然是不合理的。其實我們缺失的就是cookie和session配合的驗證。有了這個驗證過程,我們就可以實現和其他網站一樣必須登錄才能進入後臺頁面了。
先說一下這種認證的機制。每當我們使用一款瀏覽器訪問一個登陸頁面的時候,一旦我們通過了認證。服務器端就會發送一組隨機唯一的字符串(假設是123abc)到瀏覽器端,這個被存儲在瀏覽端的東西就叫cookie。而服務器端也會自己存儲一下用戶當前的狀態,比如login=true,username=hahaha之類的用戶信息。但是這種存儲是以字典形式存儲的,字典的唯一key就是剛才發給用戶的唯一的cookie值。那麽如果在服務器端查看session信息的話,理論上就會看到如下樣子的字典
{‘123abc‘:{‘login‘:true,‘username:hahaha‘}}
因為每個cookie都是唯一的,所以我們在電腦上換個瀏覽器再登陸同一個網站也需要再次驗證。那麽為什麽說我們只是理論上看到這樣子的字典呢?因為處於安全性的考慮,其實對於上面那個大字典不光key值123abc是被加密的,value值{‘login‘:true,‘username:hahaha‘}在服務器端也是一樣被加密的。所以我們服務器上就算打開session信息看到的也是類似與以下樣子的東西
{‘123abc‘:dasdasdasd1231231da1231231}
知道了原理,我們下面就來用代碼實現
COOKIE
def foo(request): print(request.COOKIES) obj=redirect("/path/") obj=HttpResponse("content") obj=render(request,"html") obj.set_cookie("key","value",max_age=60,path="/path/") obj.set_signed_cookie("key","value",max_age=60,path="/path/",salt="egonnb") request.get_signed_cookie("key",salt="egonnb"); return obj
SESSION
先在templates目錄下創建兩個html,login.html負責登錄頁面。backend頁面代表後臺頁面
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>login</title> <link rel="stylesheet" href="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/css/bootstrap.min.css"> </head> <body> <div class="container"> <form action="login.html" method="post"> <div class="form-group"> <label class="sr-only">username</label> <input type="text" class="form-control" name="username" placeholder="用戶名"/> </div> <div class="form-group"> <label class="sr-only">Password</label> <input type="password" class="form-control" name="passwd" placeholder="密碼"/> </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="http://830909.blog.51cto.com/8311014/Submit"> </div> </form> </div> <script type="application/Javascript" src="http://830909.blog.51cto.com/static/js/jquery-2.2.1.min.js"></script> <script type="application/javascript" src="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/js/bootstrap.min.js"></script> </body> </html>
backend.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>backend</title> <link rel="stylesheet" href="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/css/bootstrap.min.css"> <link rel="stylesheet" href="http://830909.blog.51cto.com/static/css/commons.css"> </head> <body> <div class="container"> <h2>cookie 內容是 {{ cookie_content }}</h2> <h2>session 內容是 {{ session_content }}</h2> <h2>登錄用戶名 :{{ username }}</h2> <a href="http://830909.blog.51cto.com/logout/">註銷</a> </div> <script type="application/javascript" src="http://830909.blog.51cto.com/static/js/jquery-2.2.1.min.js"></script> <script type="application/javascript" src="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/js/bootstrap.min.js"></script> </body> </html>
第二步 編輯app01應用下的views.py文件,編寫代碼邏輯部分
views.py
# /usr/bin/env python # coding:utf-8 from django.shortcuts import render from django.shortcuts import redirect def login(request): if request.method=="POST": username=request.POST[‘username‘] pwd=request.POST[‘passwd‘] if username==‘abc‘ and pwd==‘123‘: #設置session內部的字典內容 request.session[‘is_login‘]=‘true‘ request.session[‘username‘]=‘abc‘ #登錄成功就將url重定向到後臺的url return redirect(‘/backend/‘) #登錄不成功或第一訪問就停留在登錄頁面 return render(request,‘login.html‘) def backend(request): """ 這裏必須用讀取字典的get()方法把is_login的value缺省設置為False, 當用戶訪問backend這個url先嘗試獲取這個瀏覽器對應的session中的 is_login的值。如果對方登錄成功的話,在login裏就已經把is_login 的值修改為了True,反之這個值就是False的 """ is_login=request.session.get(‘is_login‘,False) #如果為真,就說明用戶是正常登陸的 if is_login: #獲取字典的內容並傳入頁面文件 cookie_content=request.COOKIES session_content=request.session username=request.session[‘username‘] return render(request,‘backend.html‘, { ‘cookie_content‘:cookie_content, ‘session_content‘:session_content, ‘username‘:username }) else: """ 如果訪問的時候沒有攜帶正確的session, 就直接被重定向url回login頁面 """ return redirect(‘/login/‘) def logout(request): """ 直接通過request.session[‘is_login‘]回去返回的時候, 如果is_login對應的value值不存在會導致程序異常。所以 需要做異常處理 """ try: #刪除is_login對應的value值 del request.session[‘is_login‘] except KeyError: pass #點擊註銷之後,直接重定向回登錄頁面 return redirect(‘/login/‘)
第三步,編輯mydjango目錄下的urls.py文件。設置函數與頁面的綁定關系
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^login/‘, views.login), url(r‘^backend/‘, views.backend), url(r‘^logout/‘, views.logout), ]
最後打開瀏覽器直接訪問/backend/頁面的時候直接就被重定向到了/login/
只有在輸入了正確的用戶名和密碼之後才進入到了/backend/頁面
從上圖中我們看到有一下幾點:
1、login頁面正確登錄的話,後臺頁面可以獲取到瀏覽器攜帶的cookie的。
2、第一行的sessionid其實就是cookie值
3、session的內容是加密的,從客戶端獲取不到session的內容
4、服務端可以通過預設的key值取出session的內容並打印到前段
從火狐瀏覽器裏查看cookie
django的session默認是存儲在數據庫裏的,我們再到數據庫查看一下真正session內容
從上圖中我們看到有一下幾點:
1、login頁面正確登錄的話,後臺頁面可以獲取到瀏覽器攜帶的cookie的。
2、第一行的sessionid其實就是cookie值
3、session的內容是加密的,從客戶端獲取不到session的內容
4、服務端可以通過預設的key值取出session的內容並打印到前段
從火狐瀏覽器裏查看cookie
django的session默認是存儲在數據庫裏的,我們再到數據庫查看一下真正session內容
下面我們再來最後的總結一下cookie和session的知識點
cookie:
# 1、獲取Cookie:
# request.COOKIES[‘key‘]
# request.get_signed_cookie(key, default=RAISE_ERROR, salt=‘‘, max_age=None)
# 參數:
# default: 默認值
# salt: 加密鹽
# max_age: 後臺控制過期時間
# 2、設置Cookie:
# rep = HttpResponse(...) 或 rep = render(request, ...)
#
# rep.set_cookie(key,value,...)
# rep.set_signed_cookie(key,value,salt=‘加密鹽‘,...)
# 參數:
# key, 鍵
# value=‘‘, 值
# max_age=None, 超時時間
# expires=None, 超時時間(IE requires expires, so set it if hasn‘t been already.)
# path=‘/‘, Cookie生效的路徑,/ 表示根路徑,特殊的:跟路徑的cookie可以被任何url的頁面訪問
# domain=None, Cookie生效的域名
# secure=False, https傳輸
# httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)
# 由於cookie保存在客戶端的電腦上,所以,JavaScript和jquery也可以操作cookie。
# <script src=‘/static/js/jquery.cookie.js‘></script>
# $.cookie("list_pager_num", 30,{ path: ‘/‘ });
session:
Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:
- 數據庫(默認)
- 緩存
- 文件
- 緩存+數據庫
- 加密cookie
1、數據庫Session
Django默認支持Session,並且默認是將Session數據存儲在數據庫中,即:django_session 表中。
a. 配置 settings.py
SESSION_ENGINE = ‘django.contrib.sessions.backends.db‘ # 引擎(默認)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認)
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期(默認)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之後才保存(默認)
b. 使用
def index(request):
# 獲取、設置、刪除Session中數據
request.session[‘k1‘]
request.session.get(‘k1‘,None)
request.session[‘k1‘] = 123
request.session.setdefault(‘k1‘,123) # 存在則不設置
del request.session[‘k1‘]
# 所有 鍵、值、鍵值對
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 用戶session的隨機字符串
request.session.session_key
# 將所有Session失效日期小於當前日期的數據刪除
request.session.clear_expired()
# 檢查 用戶session的隨機字符串 在數據庫中是否
request.session.exists("session_key")
# 刪除當前用戶的所有Session數據
request.session.delete("session_key")
...
2、緩存Session
a. 配置 settings.py
SESSION_ENGINE = ‘django.contrib.sessions.backends.cache‘ # 引擎
SESSION_CACHE_ALIAS = ‘default‘ # 使用的緩存別名(默認內存緩存,也可以是memcache),此處別名依賴緩存的設置
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之後才保存
b. 使用
同上
3、文件Session
a. 配置 settings.py
SESSION_ENGINE = ‘django.contrib.sessions.backends.file‘ # 引擎
SESSION_FILE_PATH = None # 緩存文件路徑,如果為None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之後才保存
b. 使用
同上
4、緩存+數據庫Session
數據庫用於做持久化,緩存用於提高效率 a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db‘ # 引擎 b. 使用 同上
5、加密cookie Session
a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.signed_cookies‘ # 引擎 b. 使用 同上
擴展:Session用戶驗證
def login(func): def wrap(request, *args, **kwargs): # 如果未登陸,跳轉到指定頁面 if request.path == ‘/test/‘: return redirect(‘http://www.baidu.com‘) return func(request, *args, **kwargs) return wrap
day18-2-django之分頁和session