django修身大法之九陽真經
cookie和session
HTTP被設計為”無態”,也就是俗稱“臉盲”。 這⼀次請求和下⼀次請求 之間沒有任
何狀態保持,我們無法根據請求的任何方面(IP地址,使用者代理等)來識別來自同⼀
⼈的連續請求。實現狀態保持的方式:在客戶端或伺服器端儲存與會話有關的資料
(客戶端與伺服器端的⼀次通訊,就是⼀次會話)
- cookie
- session
不同的請求者之間不會共享這些資料,cookie和session與請求者⼀⼀對應。
⼀、cookie
cookies 是瀏覽器為 Web 伺服器存的⼀小資訊。 每次瀏覽器從某個伺服器請求頁面時,都會自動帶上以前收到的cookie。cookie儲存在客戶端,安全性較差,注意不要儲存敏感資訊。典型應用:
- 網站登入
- 購物車
用法:
# 1.設定cookie HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False) 引數: key: cookie的名稱(*) value: cookie的值,預設是空字元 max_age:cookies的持續有效時間(以秒計),如果設定為 None,cookies 在 瀏覽器關閉的時候就失效了。 expires:cookies的過期時間,格式:"Wdy, DD-Mth-YY HH:MM:SS GMT" 如果 設定這個引數,它將覆蓋max_age。 path: cookie⽣效的路徑字首,瀏覽器只會把cookie回傳給帶有該路徑的⻚ ⾯,這樣你可以避免將cookie傳給站點中的其他的應⽤。/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的⻚⾯訪問 domain: cookie⽣效的站點。你可⽤這個引數來構造⼀個跨站cookie。如,domain=".example.com" 所構造的 cookie對下⾯這些站點都是可 讀的: www.example.com 、 www2.example.com。 如果該引數設定為None,cookie只能由設定它的站點讀取。 secure: 如果設定為 True ,瀏覽器將通過HTTPS來回傳cookie。 httponly: 僅http傳輸不能使⽤js獲取cookie #同set_cookie,不同點在於設定salt,即加鹽,加密儲存cookie資料 HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
#2 獲取cookie
HttpRequest.COOKIES.get(key)
#獲取加“鹽”的cookie
HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='',
max_age=None)
# 3刪除cookie
HttpResponse.delete_cookie(key, path='/', domain=None)
⼆、session
cookie看似解決了HTTP(短連線、無狀態)的會話保持問題,但把全部使用者資料
儲存在客戶端,存在安全隱患,
於是session出現了。我們可以 把關於使用者的資料儲存在服務端,在客戶端cookie
里加⼀個sessionID(隨機字串)。其工作流程
(1)、當用戶來訪問服務端時,服務端會生成⼀個隨機字串;
(2)、當用戶登入成功後 把 {sessionID :隨機字串} 組織成鍵值對加到cookie裡發
送給使用者;
(3)、伺服器以傳送給客戶端 cookie中的隨機字串做鍵,使用者資訊做值,儲存使用者資訊;
(4)、再訪問服務時客戶端會帶上sessionid,伺服器根據sessionid來確認使用者是否
訪問過網站
2.1 cookie和session的區別與聯絡
- 區別
- session將資料儲存與伺服器端 cookie儲存在客戶端
- cookie 儲存在客戶端,不安全,sess儲存在伺服器端,客戶端只存
sesseionid,安全 - cookie在客戶端儲存值有大小的限制,大約幾kb。session沒有限制
- 聯絡
- session 基於cookie
2.2 session配置
- 首先在settings.py中有如下配置(系統預設),
INSTALLED_APPS = [
'django.contrib.sessions',
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
]
- 進行資料遷移,生成session使用的資料庫表
2.3 session操作
- session設定
def doregister(request):
username = request.POST.get('username')
password = request.POST.get('password')
email = request.POST.get('email')
user = User()
user.username = username
user.password = md5(password.encode('utf8')).hexdigest()
user.email = email
user.save()
# 設定session
request.session['username'] = username
return render(request,"common/notice.html",context={
'code':1,
'msg':'註冊成功',
'url':'three:index',
'wait':3
})
- session獲取
def index(request):
# session獲取
username = request.session.get('username')
return render(request,'three/index.html',context=
{'username':username})
- session刪除
- clear() 清空所有session 但是不會將session表中的資料刪除
- flush() 清空所有 並刪除表中的資料
- logout() 退出登入 清除所有 並刪除表中的資料
- del req.session['key'] 刪除某⼀個session的值
def logout(request):
request.session.flush()
return redirect(reverse("three:index"))
-
session過期時間
req.session.set_expiry(5)
分頁
1. Paginator 分頁器
Paginator用於分頁,但Paginator並不具體管理具體的頁的處理,而是使用Page
物件管理具體頁面
- 建立分頁器物件
格式: Paginator(<query_set查詢集>,每頁顯示資料的條數)
- 物件的屬性
- count 分頁物件的個數
- num_pages 總頁數
- page_range 頁碼的列表
- 方法
- page(num) 返回page物件 如果給定的頁碼不存在 則丟擲異常
2. page 物件
page物件具體負責每頁的處理,包括每頁的資料,當前頁的頁碼,是否有上⼀頁
或下⼀頁等.
類別 | 名稱 | 說明 |
---|---|---|
屬性 | object_list | 當前頁碼上的所有資料 |
屬性 | number | 當前頁碼值 |
屬性 | paginator | 返回Paginator的物件 |
方法 | has_next | 是否有下⼀頁 |
方法 | has_previous | 是否有上⼀頁 |
方法 | has_other_pages | 是否有上⼀頁 或者下⼀頁 |
方法 | next_page_number | 返回下⼀頁的頁碼 |
方法 | previous_page_number | 返回上⼀頁的頁碼 |
方法 | len | 返回當前頁資料的個數 |
- 例項
#路由
url(r'^userlist/$',views.userlist,name='userlist'),
url(r'^userlist/(\d+)/$',views.userlist,name='userlist1'),
# views.py
def userlist(request,page=1):
users = User.objects.all()
# 例項化分⻚物件,⼀⻚兩條記錄
pagination = Paginator(users,2)
page = pagination.page(page) #某⼀⻚的分⻚物件
return render(request,'userlist.html',context={
'data':page.object_list, #當前⻚的資料(列表)
'page_range':pagination.page_range,#⻚碼範圍
'page':page
})
#模板⽂件
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial�scale=1">
<!-- 上述3個meta標籤*必須*放在最前⾯,任何其他內容都*必須*跟隨其後! -
->
<title>⽤戶列表</title>
<!-- Bootstrap -->
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}"
rel="stylesheet">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="bs-example" data-example-id="bordered-table">
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>⽤戶名</th>
<th>密碼</th>
<th>年齡</th>
</tr>
</thead>
<tbody>
{% for user in data %}
<tr>
<th scope="row">{{ forloop.counter }}
</th>
<td>{{ user.username }}</td>
<td>{{ user.password }}</td>
<td>{{ user.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-5">
<nav aria-label="Page navigation">
<ul class="pagination">
{% if page.has_previous %}
<li>
<a href="{% url 'app:userlist1'
page.number|add:'-1' %}" aria-label="Previous">
<span aria-hidden="true">«
</span>
</a>
</li>
{% else %}
<li class="disabled">
<span href="{% url 'app:userlist1'
page.number|add:'-1' %}" aria-label="Previous">
<span aria-hidden="true">«
</span>
</span>
</li>
{% endif %}
{% for num in pagerange %}
{% ifequal num page.number %}
<li class="active"><a href="{% url
'app:userlist1' num %}">{{ num }}</a></li>
{% else %}
<li><a href="{% url 'app:userlist1'
num %}">{{ num }}</a></li>
{% endifequal %}
{% endfor %}
{% if page.has_next %}
<li>
<a href="{% url 'app:userlist1'
page.number|add:'1' %}" aria-label="Next">
<span aria-hidden="true">»
</span>
</a>
</li>
{% else %}
<li class="disabled">
<span href="#" aria-label="Next">
<span aria-hidden="true">»
</span>
</span>
</li>
{% endif %}
</ul>
</nav>
</div>
<div class="col-md-3"></div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 外掛都依賴 jQuery,所以必
須放在前邊) -->
<script src="{% static 'bootstrap/js/jquery-1.12.4.min.js' %}">
</script>
<!-- 載入 Bootstrap 的所有 JavaScript 外掛。你也可以根據需要只加載單
個外掛。 -->
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}">
</script>
</body>
</html>