1、Django如何使用session 会话
1.1)session会话是通过中间件实现的,所以首先需要配置MIDDLEWARE
MIDDLEWARE = [
... ...
'django.contrib.sessions.middleware.SessionMiddleware',
... ...
]
1.2)默认的session会话引擎是 django.contrib.sessions.model.Session , 具体源码参考
# django/conf/global_settings.py
# The module to store session data
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
# Cache to store session data if using the cache session backend.
SESSION_CACHE_ALIAS = 'default'
所以需要在 INSTALLED_APPS 中配置
INSTALLED_APPS = [
... ...
'django.contrib.sessions',
... ...
]
然后执行 python manage.py migrate
来安装生效,使用数据库表来存储会话数据。
目前高版本的Django创建项目之后默认是采用的数据库存储,且是已经配置完成的。 如果不想使用session,可以删除如上两个配置
但是如果想使用其他的方式存储会话,就需要明确配置 SESSION_ENGINE
及相关的其他配置
2、配置会话引擎
2.1、使用数据库存储会话 具体的配置参考上面介绍
2.2、使用缓存cache存储会话 使用缓存存储,可以更好的提供性能。比如这里使用 Redis/Memcached作为缓存
# proj/settings.py
# 先配置CACHE 缓存
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
},
'as_session': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:11211',
}
}
上面配置两个缓存的目的是想说明,在Django默认的全局配置中 SESSION_CACHE_ALIAS
默认选择的是default
,除了default,当然可以选择其他的缓存,比如 as_session 的 memcached 缓存 这个时候需要明确的配置
# proj/settings.py
# Cache to store session data if using the cache session backend.
SESSION_CACHE_ALIAS = 'as_session'
# The module to store session data
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
2.3、使用文件存储会话
# proj/settings.py
# The module to store session data
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
# 默认是 tempfile.gettempdir()
# 一定要保证对应的程序有权限读写
SESSION_FILE_PATH = '/data/proj/file_session.txt'
2.4、使用cookie存储会话
# proj/settings.py
# The module to store session data
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
该会话引擎会用到项目配置的 SECRET_KEY
已经Django内置的 加密工具(参考 https://docs.djangoproject.com/zh-hans/4.1/topics/signing/)
2.5、特殊的 cached_db 存储会话 其实除了上面提到的四种方式之外,还有另外一种组合方式cached_db
通过阅读源码发现
# django.contrib.sessions.backends.cached_db.py
from django.conf import settings
from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.core.cache import caches
KEY_PREFIX = "django.contrib.sessions.cached_db"
class SessionStore(DBStore):
"""
Implement cached, database backed sessions.
"""
cache_key_prefix = KEY_PREFIX
def __init__(self, session_key=None):
self._cache = caches[settings.SESSION_CACHE_ALIAS]
super().__init__(session_key)
... ...
源码中 DBStore 其实就是 基于数据库的会话存储,然后这里的 cached_db 继承自DBStore,然后同时新增了 self._cache
是基于缓存的会话存储方式。
视图中使用session
在视图中可以直接通过 request.session
使用,它实质上是 HttpResquest对象的 session属性。
为何能直接使用呢?主要是通过 SessionMiddleware 中间件来生效的
# django/contrib/sessions/middleware.py
from django.utils.deprecation import MiddlewareMixin
class SessionMiddleware(MiddlewareMixin):
# RemovedInDjango40Warning: when the deprecation ends, replace with:
# def __init__(self, get_response):
def __init__(self, get_response=None):
super().__init__(get_response)
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
# 核心代码
request.session = self.SessionStore(session_key)
然后所以的 会话引擎都是继承自 SessionBase
,该类提供了一些标准的字典方法
# django/contrib/sessions/backends/base.py
class SessionBase:
def __getitem__(self, key):
# val = request.session[key]
... ...
def __setitem__(self, key):
# request.session[key] = val
... ...
def __delitem__(self, key):
# del request.session[key]
... ...
def __contains__(self, key):
# key in request.session
... ...
def get(self, key, default=None):
# val = request.session.get('key', 'default_val')
... ...
def pop(self, key, default=__not_given):
# val = request.session.get('key', 'default_val')
... ...
... ...
还有很多方法,比如 set_expiry() \ cycle_key() 等等,感兴趣的可以自己查阅源码
???? 在实际使用过程中有几个注意事项
1、强烈建议使用 JSON 序列化,及时是自定义序列化时。这也是Django序列session是默认使用的方式。
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'
2、request.session使用普通的Python字符串作为字典键
,请勿使用下划线开头的,这个是保留给Django内部使用的
3、不要去覆盖 request.sesesion 就当成普通的 Python字典来使用就好。
使用举例
def login(request):
user = User.objects.get(username=request.POST['username'])
if user.check_password(request.POST['password']):
# 登录成功之后,保存用户ID到session中,用于后续判断
request.session['user_id'] = user.id
return HttpResponse("You're logged in.")
else:
return HttpResponse("Your username and password didn't match.")
在视图外使用会话
核心是在自己的代码中导入需要的会话存储引擎,且建议使用 import_module的方式,
# 直接导入
from django.contrib.sessions.backends.db import SessionStore
s = SessionStore()
# 建议 import_Module方式
>>> from importlib import import_module
>>> from django.conf import settings
>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
>>> s = SessionStore()
>>> s
<django.contrib.sessions.backends.db.SessionStore object at 0x102ac6160>
>>> s['username'] = 'James'
>>> s.session_key
>>> s.create()
>>> s.session_key
'v75esxsbrye4efrl3tppsp6w443jawq5'
>>> s2 = SessionStore(session_key='v75esxsbrye4efrl3tppsp6w443jawq5')
>>> s2['username']
'James'
>>> s2.session_key
'v75esxsbrye4efrl3tppsp6w443jawq5'
扩展介绍 - 会话保持
在session相关的配置中,SESSION_EXPIRE_AT_BROWSER_CLOSE
是用来控制会话是使用 持久会话
还是Browser-length(基于浏览器是否关闭)
- • SESSION_EXPIRE_AT_BROWSER_CLOSE=True 时 Django使用
Browser-length
即浏览器关闭了,session自动过期
- • SESSION_EXPIRE_AT_BROWSER_CLOSE=False 时 Django使用
持久会话
即浏览器关闭了,session经过 SESSION_COOKIE_AGE
后过期
当然除了上面这个全局变量控制session过期,也可以显式的使用 request.session 的 set_expiry()
在每个会话级别上覆盖
扩展介绍 - 清理会话
1、如果会话是使用的 db 或者 file 的方式进行存储,那么Django是没有提供过期会话自动清除的功能,需要自定义定期清除过期会话。
建议使用Django提供的 clearesessions 内置命令进行
2、如果是使用的 cache或者cookie的方式,其本身就有过期自动删除的功能。不需要人为介入
关于Django session相关的知识就介绍到这里,欢迎关注微信公众号 DailyJobOps
或者添加1209755822 交流