Django中Session的使用

0. 前言

Session中的数据保存在服务端,而客户端的Cookie中含有一个session ID(而不是数据本身)。

1. 启用Session

Session作为Django中的一个中间件(middleware)。为了启用Session,需要在settings.py中确保:

  • Session被加入中间件
    Django中Session的使用
  • Session被加入INSTALLED_APPS
    Django中Session的使用

对于以默认方式创建的Django项目,以上设置都是被默认配置好的。

2. 设置Session引擎

默认情况下,Django将Session存入数据库中。为了追求更高的速度,可以把Session存到别的地方,比如文件系统和Cache中。

2.1 基于数据库的Session

如果需要将Session存入数据库中,在INSTALLED_APPS中加入:
Django中Session的使用
配置完毕后,需要执行 manage.py migrate 。

2.2 基于Cache的Session

(知识盲区,之后再更新)

2.3 基于文件系统的Session

在settings.py中设置SESSION_ENGINE为:
Django中Session的使用
除此之外也可以设置Session存放的路径,默认为临时目录,修改 SESSION_FILE_PATH 属性即可。

2.4 基于Cookie的Session

在settings.py中设置SESSION_ENGINE为:
Django中Session的使用
Session数据将会被加密存储在客户的Cookie中,需要使用到SECRET_KEY这个选项进行加密。

3. 在视图中使用Session

当Session中间件被**后,每一个HttpRequest对象都会有一个session属性,该属性可如同字典一样操作
session对象有以下方法:

  • get()
    与字典中的get()相同,当键不存在时不抛出异常而是返回默认值。
  • flush()
    删除Session中所有数据以及Session Cookie,当你需要确保之前Session中的数据不能再次被读取时使用,例如用户的退出登录。
  • get_session_cookie_age()
    返回Session Cookie的生存时间,单位为秒。
  • set_expiry(value)
    设置Session的过期时间,如果value为整数,指定秒数后过期;如果value为timedelta对象,将在指定时间间隔后过期;如果value为0,当用户浏览器关闭后Session Cookie会过期;如果value为None,Session将会使用全局Session过期策略。

:读取Session并不会影响生存时间,只有当修改Session才会使得重新计算生成时间。

  • get_expiry_age()
    返回距离Session过期的秒数,如果Session被设为浏览器关闭时过期,则返回值为SESSION_COOKIE_AGE(2周)。

3.1 Session的序列化

默认情况下,Django使用JSON来序列化Session,不推荐使用pickle来序列化,因为pickle的反序列过程中可能会导致任意代码被执行。
需要注意的是,JSON只支持字符串作为key,因此request.session对象中也需要将字符串作为key。

3.2 示例演示及分析

以下是一个提交评论的例子,每个用户只允许提交一次评论。
视图函数为:
Django中Session的使用
在第一次访问网址以后,查看数据库中的django_session表,发现多了一条记录:
Django中Session的使用
当前时间是5月1日,显然Session的存活时间为两周(14天)。

然后在浏览器中按F12打开开发人员工具,查看Cookie信息:
Django中Session的使用
可以看出,该Cookie即为sessionid,它的存活时间也是14天,Cookie的值与数据库中session_key字段的值一致。

此时刷新页面,页面显示已经发表过评论的提示,同时数据库中不再增加新的记录(废话)。
当然了,关闭浏览器再打开,状态仍然被保持,因为Cookie没有到过期时间。

下面开始发散性实验:
首先手动将浏览器中的Cookie清了,然后刷新页面。此时产生一个新的Session,数据库中增加了一条新记录:
Django中Session的使用
然后,清空数据库,再刷新页面。此时原有的状态丢失,然后浏览器中的Cookie sessionid变成了一个新的值,数据库中增加了一条新的记录。

接下来通过session的set_expiry()方法将生存时间设置为0,也就是当浏览器关闭后过期
刷新页面,在浏览器中查看Cookie,可以看到该Cookie的过期时间为“会话”:
Django中Session的使用
接着在数据库中查看记录,发现数据库中记录的过期时间仍然是14天以后:
Django中Session的使用
此时我关闭浏览器再打开,则Cookie失效。此时创建一个新的Session,可以发现数据库中多了一条记录。

最后,我把数据库中的过期时间往前调,使其已经过期,然后刷新浏览器,发现原有的状态失效了。

由此看出,Session分为两个部分,服务器端和客户端,哪一方失效了都不行。即使将Session的生存期被设为直到浏览器关闭,那只是它在客户端浏览器中的生存期,在数据库中它的生存期仍然为14天。

3.3 注意事项

Django不会自动清除数据库中过期的Session记录,需要手动清除

4. 在视图外使用Session

主要用途是查看数据库中的Session记录,可以查看Session的键、过期时间、维护的内容。
注意,Session中的内容被编码了,需要使用get_decoded()方法来解码。
Django中Session的使用

5. 浏览器生存期Session VS 持久性Session

在settings.py中,可以设置SESSION_EXPIRE_AT_BROWSER_CLOSE,它的默认值为False,表示Cookie被一直存储在浏览器中直到SESSION_COOKIE_AGE,如果设置为True,表示Session生存时间为浏览器,当浏览器关闭时Cookie便会过期。这个设置是全局性的设置,可以通过显式调用session对象的set_expiry()方法来个性化配置,正如3.2节提到的那样。

6. 清除过期的Session记录

Django并不会自动清除数据库中过期的Session记录,可以使用clearsessions这个工具来手动清除。
具体方法是:点击Pycharm的菜单Tools->Run manage.py Task,输入clearsessions并执行即可。