Django Session 原理及配置和使用

Django Session 原理及配置和使用

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 或者添加QQ 1209755822 交流

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 144,247评论 1 305
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 61,830评论 1 258
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 95,531评论 0 214
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 41,345评论 0 183
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 49,160评论 1 260
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,936评论 1 178
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,538评论 2 275
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,291评论 0 168
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 29,162评论 6 237
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,654评论 0 214
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,401评论 2 217
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,747评论 1 232
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,297评论 1 33
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,206评论 2 213
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,670评论 3 213
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,661评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,089评论 0 169
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,677评论 2 233
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,819评论 2 237

推荐阅读更多精彩内容

  • 点我查看本文集的说明及目录。 本项目相关内容包括: 实现过程: CH7 创建在线商店 CH8 管理支付和订单 CH...
    学以致用123阅读 4,819评论 8 9
  • cookie和session的区别 Cookie是保存在用户浏览器端的键值对,Session是保存在服务器端的键值...
    汪菲宇阅读 911评论 0 0
  • 一、会话跟踪 首先为什么会存在这种技术,因为http为无状态协议,就是说浏览器这一步请求并不知道上一步请求所包含的...
    唯老阅读 459评论 0 5
  • 模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚...
    riverstation阅读 1,998评论 0 8
  • Cookie & Session 由于HTTP协议的无状态性,每次连接结束后HTTP连接都会自动断开,因此每一个来...
    JunChow520阅读 349评论 0 1