Session会话管理
Session主要用于身份验证、偏好设置、购物车等场景,Django的session模块提供了一种在服务端存储用户会话状态的机制,它提供了多种存储后端供我们选择,包括基于数据库和基于Redis的Session机制,同时该模块还被设计为了可插拔的模式,如果我们完全不使用它(例如我们仅使用JWT机制)也可以将其关闭。这篇笔记我们对Django的session模块进行简单介绍。
Session机制原理
Django的session模块的实现基于以下几个机制。
会话ID(SessionID):当用户首次访问网站时,Django会为其生成唯一的会话ID,并将其存储在客户端的Cookie中。
存储会话数据:实际的会话数据会被存储在服务端,session模块支持配置数据存储到多种后端,包括数据库、缓存、文件等。
数据访问:在用户的后续请求中,Django会根据附带在请求中Cookie内的会话ID检索存储在服务端的会话数据。
SessionID在浏览器侧的Cookie信息如下图。

具体来说,session模块有关的功能其实都是通过中间件django.contrib.sessions.middleware.SessionMiddleware实现的,默认创建工程时,已经自动帮我们添加这个组件了,如果需要关闭session模块,移除这个中间件即可。
写入和访问Session
下面例子中,我们向Session写入一个布尔类型值。
from django.shortcuts import render
def index(request):
# 写入Session
request.session["is_login"] = True
return render(request, 'index.html')
读取Session也是类似的,直接访问request.session即可。
注意:对于Session的设置有一个暗坑,默认情况下,Session不会每一次请求都更新,仅仅会在Session的内容被修改后,Session中会有一个标识request.session.modified被自动置为True,此时Session才会更新。然而,如果我们对Session中的对象进行“深层”的修改(比如对session['user']对象内的属性进行修改,而不是user这个Session中相对外层的引用),这个标识就不会自动更新!该问题的解决办法有2种:
- 手动设置
request.session.modified = True,但这会使代码变得冗余。 - 在
settings.py中加入配置SESSION_SAVE_EVERY_REQUEST = True,使得每次请求都会更新Session,但如果使用基于数据库的Session会使得数据库压力显著增大,最好配合Redis等中间件使用。
在模板中访问Session
一种常见需求是顶部导航的登陆判断,如果已经登陆显示用户名和用户菜单,如果未登录显示“请登录”,那么此时显然我们需要在模板中访问Session并判断用户是否已经登录。下面是一个例子模板代码,假设用户登录后,我们会将user对象存入Session中,模板中可以如下进行判断。
{% if 'user' in request.session %}
...
{% endif %}
Django模板中也实现了类似JSP的内置对象,通过request.session就可以访问Session内容了。
Session的超时和清除
关闭浏览器时清除Session
对于Session,大多数Web框架的处理方式都是关闭浏览器时过期,但注意Django默认不是这样的,我们可以在settings.py中设置如下选项来实现这一配置。
# 关闭浏览器时让Session过期
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
删除Session字段
我们也可以手动删除一个Session中的字段,下面例子中,我们删除了Session中的user字段。
request.session.pop('user')
手动设置Session的超时时间
下面例子中,Session会在5秒后超时。
request.session.set_expiry(5)
注:经过实际测试,这个超时时间似乎不是太准确,即使指定5秒超时,可能还是10秒后才真的起作用。
Session的存储后端
默认Django会在数据库中持久化Session,其表名为django_session,如果需要手动清空服务端的Session,直接清空该表就可以了。但如果对性能有一些要求,我们可能需要将Session存储到Redis、Memcached等分布式缓存系统。
使用Redis存储Session
大量的请求会给数据库造成不小的压力,在有性能要求的场景下,像Redis这种分布式缓存系统存储Session具有高性能、高可用的特点。不过Django默认没有集成Redis的客户端,我们需要先用pip安装Django的Redis插件。
pip install django-redis
此外还需要在settings.py中配置Redis缓存,并指定Session使用Redis缓存作为存储后端。
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
LOCATION中配置的是Redis服务器的地址,其中最后的/0指定使用0号数据库。配置好后,我们可以尝试在代码中设置Session。在redis-cli工具中,我们可以看到类似如下的键值对。
