# 狀態保持
## 狀態保持
* http協議是無狀態的:每次請求都是一次新的請求,不會記得之前的通信的狀態
* 客戶端與服務端的一次通信,就是一次會話
* 實現狀態保持的方式,在客戶端或服務器端存儲于會話有關的數據
* 儲存方式包括cookie、session、會話一般指session對象
* 使用cookie,所有數據存儲在客戶端,注意不要儲存敏感信息
* 推薦使用session方式,所有數據存儲在服務器端,在客戶端cookie中存儲session\_id
* 狀態保持的目的是在一段時間內跟蹤請求者的狀態,可以實現跨頁米娜訪問當前請求者的數據
* 注意:不同的請求者之間不會共享這個數據,與請求者一一對應
## 啟用session
* 使用django-admin startproject創建的項目默認啟用
* 在settings.py文件中
* 在INSETALLED\_APPS列表中添加
```text
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
# 添加
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
在MIDDLEWARE_CLASSES列表中添加
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
#添加
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```
* 禁用會話:刪除上面的指定的兩個值,禁用會話將節省一些性能消耗
### 使用session
* 啟用會話后,每個HttpRequest對象將具有一個session,是一個類字典對象
* get\(key,default=None\):根據鍵獲取會話的值
* clear\(\):清除所有會話
* flush\(\):刪除當前的會話數據并刪除會話Cookie
* del request.session\['memeber\_id'\]:刪除會話
* 在views.py文件創建視圖
```text
from django.shortcuts import render,redirect
from django.urls import reverse
def index(request):
name = request.session.get('name',default="游客")
print(request.session.get('name'),'2')
return render(request,"myapp/index.html",{'name':name})
def login(request):
return render(request,'myapp/login.html')
def login_handle(request):
request.session['name'] = request.POST['name']
print(request.POST['name'])
return redirect(reverse("myapp:index"))
def logout(request):
request.session.flush()
return redirect(reverse('myapp:index'))
```
* 配置url
```text
主url:
from django.conf.urls import include,url
url(r'',include('myapp.urls',namespace='myapp')),
應用url:
from django.conf.urls import url
from . import views
url(r'login/$', views.login, name='login'),
url(r'login_handle/$', views.login_handle, name='login_handle'),
url(r'logout/$', views.logout, name='logout')
```
* 創建模板index.html
```text
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>session會話</title>
</head>
<body>
<h1>Hello,{{ name }}</h1>
<hr/>
<a href="{% url 'myapp:login' %}">登錄</a>
<a href="{% url 'myapp:logout' %}">登出</a>
</body>
</html>
```
* 創建模板login.html
```text
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="{% url 'myapp:login_handle' %}">
姓名: <input type="text" name="name"/><br />
<input type="submit" value="value"/>
</form>
</body>
</html>
```
## 會話過期時間
* set\_expiry\(value\):設置會話的超時時間
* 如果沒有指定,則兩個星期后過期
* 如果value是一個整數,會話將在values秒沒有活動后過期
* 如果value是一個imedelta對象,會話將在當前時間加上這個指定的日期/時間過期
* 如果value為0,name會話的cookie將在用戶的瀏覽器關閉時過期
* 如果value為None,name會話永不過期
* 修改視圖中login\_handle函數,查看效果
```text
def login_handle(request):
request.session['name'] = request.POST['name']
print(request.POST['name'])
# request.session.set_expiry(10)
# request.session.set_expiry(timedelta(days=5))
# request.session.set_expiry(0)
# request.session.set_expiry(None)
return redirect(reverse("myapp:index"))
```
## 存儲session
* 使用存儲會話的方式,可以使用settings.py的SESSION\_ENGINE項指定
* 基于數據庫的會話:這是django默認的會話存儲方式,需要添加django.contrib.session到的INSTALLED\_APPS設置中,運行manage.py migrate在數據庫中安裝會話表,可顯示指定為
```text
SESSION_ENGINE='django.contrib.sessions.backends.db'
```
* 基于緩存的會話:只存在本地內在中,如果丟失則不能找回,比數據庫的方式讀寫更快
```text
SESSION_ENGINE='django.contrib.sessions.backends.cache'
```
* 可以將緩存和數據庫同時使用:優先從本地緩存中獲取,如果沒有則從數據中獲取
```text
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
```
## 使用Redis緩存session
* 安裝 django-redis、django-redis-session
* pip install django-redis
* pip install django-redis-sessions
* 修改settings中的配置
```text
# 緩存
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
REDIS_TIMEOUT=7*24*60*60
CUBES_REDIS_TIMEOUT=60*60
NEVER_REDIS_TIMEOUT=365*24*60*60
```
* 測試緩存是否成功
```text
輸入交互命令:python manage.py shell
In [1]: from django.core.cache import cache #引入緩存模塊
In [2]: cache.set('v', '555', 60*60) #寫入key為v,值為555的緩存,有效期30分鐘
Out[2]: True
In [3]: cache.has_key('v') #判斷key為v是否存在
Out[3]: True
In [4]: cache.get('v') #獲取key為v的緩存
Out[4]: '555'
```
* redis數據庫更多詳細:[http://django-redis-chs.readthedocs.io/zh\_CN/latest/\#cache-backend](http://django-redis-chs.readthedocs.io/zh_CN/latest/#cache-backend)
* 管理redis的命令
```text
下載地址:https://github.com/MicrosoftArchive/redis/releases
啟動:net start redis
停止:net stop redis
重啟:net restart redis
使用客戶端連接服務器:redis-cli
keys *:查看所有的連接
get name:獲取指定鍵的值
del name:刪除指定名稱的鍵
```