Django学习纪录 12.Cookies与Sessions

之前有在用Django写一些小网站,现在暑假想说再来複习一下之前买的这本书
http://img2.58codes.com/2024/20118889bj9fH1vhuR.jpg
于是我就把它写成一系列的文章,也方便查语法
而且因为这本书大概是2014年出的,如今Django也已经出到2.多版
有些内容也变得不再支援或适用,而且语法或许也改变了
所以我会以最新版的Python和Django来修正这本书的内容跟程式码

目录:django系列文章-Django学习纪录

12. Cookies与Sessions

12.1 Http协定的不足

单纯的http协定无法让网站保持着某些资讯跟状态,因为它就只是非常制式地接收要求,回应要求
每一次的要求,每一次的回应都是独立的,因为http无法记录任何状态,它并不能保持着上一次要求所带来的任何有用资讯
当然,透过GET与POST我们依然可以将资料透过新的request带到下一个页面,但是,这样相当麻烦,而且没有效率
将Http协定的不足分为以下三点:

12.1.1 根本不知道使用者

伺服器不知道有某用户
使用资料库纪录用户的资讯便可解决

12.1.2 知道使用者但不会做资料比对

即使伺服器记录了用户的资讯,但不做比对,也是认不出用户的
这时就需要仰赖登入及辨识了

12.1.3 知道使用者,也会比对,但使用者在每一次的请求中都要比对

只要用户每次都辛苦地提供资讯,伺服器就可以辨识的出用户
但我们不希望在同一个网站中每次要求一个新页面时,都要重新登入一次
倒不如让伺服器给用户一块饼乾,只要你拿这块饼乾出来,我就可以认得你

12.2 Cookies-好饼乾,不吃吗?

这块饼乾就是大家耳熟能详的cookie了
cookie是伺服器储存在浏览器的一小段讯息,它用来记住一些暂时性资讯并且能让使用者跨页面使用,每一次使用者透过浏览器向伺服器提出要求时,都会双手奉上伺服器在稍早存在客户端(浏览器)的cookie
透过这些cookies,伺服器便能掌握使用者的状态,直到cookie失效那天
一个cookie其实就只是一个键值对,包含了cookie的名称和cookie的值
在django中操作cookie就类似于使用字典那样

12.2.1 设置cookie

def set_c(request):    response = HttpResponse('Set your lucky_number as 8')    response.set_cookie('lucky_number',8)    return response

set_cookie第一个参数指定cookie的键,第二个参数指定cookie的值

12.2 读取cookie

def get_c(request):    if 'lucky_number' in request.COOKIES:        return HttpResponse('Your lucky_number is {0}'.format(request.COOKIES['lucky_number']))    else:        return HttpResponse('No cookies.') 

12.2.3 饼乾的问题

cookies是储存在浏览器端的,而用户可以关闭cookies的功能,这会导致许多行为无效化
Http协定是明文协定,cookies在传输过程中容易被拦截、窜改、伪造等,并不安全
为了解决这些问题,引进了Session的机制

12.3 Session

session之所以能够解决这些问题是因为它是把资讯储存在伺服端
那为何不直接将资料存在资料库中?因为这只是暂时性的资讯,实在是没有必要
不过django的session还是有用到资料库的,所以在使用时要安装app,也要同步资料库
session跨页面生存的方式:

session会透过cookie储存一段用以辨识的ID,cookie可以跨页面生存,session自然也可以啰,透过这个ID,指令搞便可以去伺服端将我们需要的资料取出来,这个方式跟纯粹使用cookie来储存资讯的方式不同,因为现在这个cookie只储存session的ID(而且是加密过的),我们的资料不会直接暴露给浏览器端我们一样可以透过url查询字符的方式,将session ID附上,这对于cookie功能被浏览器端关闭时特别有用
我们先使用预设的第一种

12.3.1 安装Session App

settings.py

INSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions', # <-确认有安装    'django.contrib.messages',    'django.contrib.staticfiles',    'restaurants',]MIDDLEWARE = [    'django.middleware.security.SecurityMiddleware',    'django.contrib.sessions.middleware.SessionMiddleware', # <-确认有安装    'django.middleware.locale.LocaleMiddleware',    'django.middleware.common.CommonMiddleware',    'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',]

如果第一次使用session记得要同步一下资料库才能启用session

python manage.py migrate

12.3.2 使用Session

def use_session(request):    request.session['lucky_number'] = 8 # 设置lucky_number    if 'lucky_number' in request.session:        lucky_number = request.session['lucky_number'] # 读取lucky_number        response = HttpResponse('Your lucky_number is ' + str(lucky_number))    return response

使用session时的规则:
1.使用字串作为session的键值
2.不要任意以底线作为session键值字串的开头
3.不要对session及其属性赋值
如果要删除session

del request.session['lucky_number']

即可

12.3.3 Session资料库

打开shell

python manage.py shell
>>> from django.contrib.sessions.models import Session>>> s = Session.objects.all()[0]>>> s.expire_datedatetime.datetime(2019, 7, 31, 10, 20, 57, 569595, tzinfo=<UTC>)

expire_date是该session的有效期限,当超过这个时间时,session即失效

>>> s.session_data'ODdhMzQxMWY0MzU0Nzg5YjgwYmRkZTZlZjJmYTBmZjBiMmQ4MzJkNzp7Il9hdXRoX3VzZXJfaWQiOiIxIiwiX2F1dGhfdXNlcl9iYWNrZW5kIjoiZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmQiLCJfYXV0aF91c2VyX2hhc2giOiJmMTQwNzM4OThkNzRlZjVjOWE1NzFiZmZhZDJhYjI1ZjYxNDgzNGQyIn0='>>> s.get_decoded(){'_auth_user_id': '1', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', '_auth_user_hash': 'f14073898d74ef5c9a571bffad2ab25f614834d2'}

session_data是经过编码的,必须利用get_decoded()方法来取得编码后的资料,而这会是一个字典

12.3.4 Session cookie

session ID 是透过cookie来保存的,这个cookie就叫session cookie
我们可以透过sessionid这个cookie名称来取得cookie,而他的值就是编码后的session ID
撰写视图函式

from django.contrib.sessions.models import Sessiondef session_test(request):    sid = request.COOKIES['sessionid']    s = Session.objects.get(pk=sid)    s_info = 'Session ID:' + sid + '<br>Expire_date:' + str(s.expire_date) +              '<br>Data:' + str(s.get_decoded())    return HttpResponse(s_info)

利用request.COOKIES来取得sessionid这个cookie的值,也就是session ID,接着我们利用模型的get方法去找到在资料库中符合该ID的sessions(Session资料表的主键pk即为session id),最后我们把expire_date和session的内容都印出来
在页面上按右键->检查,就可以查看cookie及session资讯
http://img2.58codes.com/2024/20118889JqK3omSRUj.png
另一个方法

def session_test(request):    sid = request.COOKIES['sessionid']    sid2 = request.session.session_key    s = Session.objects.get(pk=sid)    s_info = 'Session ID:' + sid + '<br>SessionID2:' + sid2 + '<br>Expire_date:' + str(s.expire_date) + '<br>Data:' + str(s.get_decoded())    return HttpResponse(s_info)

http://img2.58codes.com/2024/2011888997zmMJLlt1.png
结果两个方式拿到的session ID也是一样的
这种预设以cookie记录session ID来达成跨页面的方式虽然方便,但读者们还是要确认使用者端的cookie功能是否被开启,透过以下步骤来测试:
1.利用HttpRequest.session.set_test_cookie()设置测试cookie
2.利用HttpRequest.session.test_cookie_worked()来检查cookie是否被允许使用
3.利用HttpRequest.session.delete_test_cookie()来删除测试cookie
如果cookie未被开启,那我们只得利用URL查询的方式,去传递session ID,不过这会相当麻烦

12.3.5 Session的持续性

可以在settings.py中设定参数
参数 | 意义 | 预设值
------------- | -------------
SESSION_EXPIRE_AT_BROWSER_CLOSE | 决定session是否在浏览器关闭时结束 | False
SESSION_COOKIE_AGE | session(cookie)的有效时间 | 1209,600秒,两週

12.3.6 用Session储存模型物件

views.py

...def list_restaurants(request):    restaurants = Restaurant.objects.all()    request.session['restaurants'] = restaurants  # 试着利用session保存模型物件    return render_to_response('restaurants_list.html', locals())...

结果出现错误
http://img2.58codes.com/2024/20118889IHViaimb4X.png
在settings.py中加入

SESSION_SERIALIZER = 'django.contrib.sessions.serializers' + '.PickleSerializer'

就能解决了
pickle是python储存物件的一种特殊机制,可以将物件讯息化变成一连串的编码,方便储存或纪录,而从这些编码要回复为物件时也是需要经由pickle才能回复,这个特殊的机制有个名词:持久化,这里我们要保存的是模型物件,无法用json格式转化储存,所以改为PickleSerializer

上一篇:Django学习纪录 11.表单的验证与模型化

下一篇:Django学习纪录 13.用户的登入与登出


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章