Django中request.session直接通过键值读写即可,自动处理序列化、签名与过期;推荐用get()避免KeyError,删除需显式操作;重定向时可能因延迟写cookie导致读不到新数据;后端可配db/cache/cached_db,API不变;仅存基础类型或ID,勿存模型实例等不可序列化对象。

怎么用 request.session 存取数据
直接赋值或读取字典式键值就行,Django 自动处理序列化、签名、存储和过期。不需要手动调用 save(),除非你禁用了 SESSION_SAVE_EVERY_REQUEST 且没修改 session 内容。
-
request.session['user_id'] = 123—— 写入后下次请求就能读到 -
uid = request.session.get('user_id')—— 推荐用get(),避免 KeyError -
del request.session['user_id']或request.session.pop('user_id', None)—— 删除要显式操作 - 存非 JSON 序列化类型(如 datetime、自定义类)会报
PickleError,只建议存基础类型(str、int、dict、list、bool)
为什么 request.session 有时读不到刚写的数据
常见于重定向场景:写完 session 立即 redirect(),但响应还没发 cookie,浏览器下个请求就带不上新 sessionid —— Django 默认延迟写入 cookie,直到响应头真正发出。
- 确保视图返回的是
HttpResponse或其子类(比如redirect()返回的HttpResponseRedirect是 OK 的) - 不要在中间件或信号里提前读写 session,容易因执行时机错乱导致读空
- 如果用了
request.session.modified = True强制标记已改,注意它不触发写入,只是影响是否发送 session cookie - 调试时检查响应头有没有
Set-Cookie: sessionid=...,没有说明 session 没真正提交
request.session 和数据库、缓存后端的关系
session 数据存在哪,取决于 SESSION_ENGINE 设置,默认是 django.contrib.sessions.backends.db,也就是每读写都查一次数据库 —— 并不慢,但高并发下可能成瓶颈。
- 想用 Redis?装
django-redis,设SESSION_ENGINE = 'django.contrib.sessions.backends.cache'或'django.contrib.sessions.backends.cached_db' -
cached_db是推荐折中:读走 cache,写双写 cache + db,断电也不丢数据 - 改后端不影响代码,
request.sessionAPI 完全不变 - 注意:
cache模式下 session 可能被 LRU 清掉,用户莫名登出;db模式下记得定期运行python manage.py clearsessions
哪些值不能往 request.session 里塞
不是所有 Python 对象都能存。Django session 序列化默认用 pickle(db 后端)或 JSON(cache 后端),但即使启用了 pickle,也强烈不建议存复杂对象。
- 模型实例(
User对象)—— 会 pickle 成二进制,反序列化可能失败,且含敏感字段 - 文件句柄、线程锁、socket 连接等运行时资源 —— 下次请求根本无法还原
- lambda、嵌套函数、本地作用域闭包 —— pickle 不支持
- 正确做法:只存 ID(如
request.session['user_id'] = user.id),需要时再查库
session 不是临时数据库,它只该存轻量、可预测、可丢弃的状态标识。真要传复杂结构,先转成 dict/list,再确认能被 JSON.dumps() 过。









