settings里有关中间件的配置
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'rbac.service.middleware.M1' ] from django.contrib.sessions.middleware import SessionMiddleware
能够看到settings中都是字符串形式的,咱们经过from django.contrib.sessions.middleware import SessionMiddleware导入,并查看SessionMiddleware类的内容html
SessionMiddleware
import time from importlib import import_module from django.conf import settings from django.contrib.sessions.backends.base import UpdateError from django.core.exceptions import SuspiciousOperation from django.utils.cache import patch_vary_headers from django.utils.deprecation import MiddlewareMixin from django.utils.http import cookie_date class SessionMiddleware(MiddlewareMixin): def __init__(self, get_response=None): self.get_response = 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) def process_response(self, request, response): """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie or delete the session cookie if the session has been emptied. """ try: accessed = request.session.accessed modified = request.session.modified empty = request.session.is_empty() except AttributeError: pass else: # First check if we need to delete this cookie. # The session should be deleted only if the session is entirely empty if settings.SESSION_COOKIE_NAME in request.COOKIES and empty: response.delete_cookie( settings.SESSION_COOKIE_NAME, path=settings.SESSION_COOKIE_PATH, domain=settings.SESSION_COOKIE_DOMAIN, ) else: if accessed: patch_vary_headers(response, ('Cookie',)) if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) # Save the session data and refresh the client cookie. # Skip session save for 500 responses, refs #3881. if response.status_code != 500: try: request.session.save() except UpdateError: raise SuspiciousOperation( "The request's session was deleted before the " "request completed. The user may have logged " "out in a concurrent request, for example." ) response.set_cookie( settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None, ) return response
初始化方法
咱们先看这个类的init初始化方法数据库
def __init__(self, get_response=None): self.get_response = get_response engine = import_module(settings.SESSION_ENGINE) self.SessionStore = engine.SessionStore
首先定义self.get_response=get_response这里默认为Nonedjango
而后经过import_module导入模块,该方法能够经过字符串导入模块cookie
咱们到settings中找到SESSION_ENGINE参数的值session
这里engine就等于上面导入的模块dom
而后self.SessionStore = engine.SessionStore,咱们能够看看engine模块中都有什么函数
能够看到SessionStore就是一个类post
self.SessionStore就是这个类学习
process_request
def process_request(self, request): session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME) request.session = self.SessionStore(session_key)
首先定义一个session_keythis
这里的session_key其实就是COOKIE里带的以sessionid为key,随机字符串为值的值
当咱们第一次访问时其实session_key的值应该是None
而后定义request.session,咱们能够看到咱们一直使用的request.session实际上是self.SessionStore这个类实例化出的对象
实例化的过程执行了什么呢
SessionStore类初始化时调用了其父类的__init__方法
父类的__init__方法首先定义了self._session_key=session_key,第一次访问和默认状况都是None
而后定义了两个变量self.accessed和self.modified都是False
最后的self.serializer是序列化时的方法,咱们暂时不看
到此process_request就执行完了
视图函数
在执行视图函数时咱们可能会对request.session进行操做,例如登陆成功后咱们要作如下设置
request.session["user_id"] = user.pk
咱们在学习面向对象的知识时曾经学过这种相似于操做字典同样的方法,在对象的父类中须要有__getitem__,__setitem__,__delitem__方法,才能这么操做,而这么操做了也就至关于执行了前面的几个方法
在SessionStore的父类SessionBase中咱们找到了这几个方法
咱们这里的操做其实就是执行的下面的代码
def __setitem__(self, key, value): self._session[key] = value self.modified = True
首先self._session[key] = value,这个self._session是个什么呢
继续在SessionBase类中查找
从上面的代码能够看出self._session其实就是self._session_cache,若是第一次访问,self._session_cache不存在,因此会抛出异常,走except的内容,给self._session_cache赋一个空字典,这里给这个字典添加了咱们设置的键值对
而后将self.accessed和self.modified的值变为True
当视图函数执行完成后,咱们又要走中间件的process_response方法
process_response
def process_response(self, request, response): """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie or delete the session cookie if the session has been emptied. """ try: accessed = request.session.accessed modified = request.session.modified empty = request.session.is_empty() except AttributeError: pass else: # First check if we need to delete this cookie. # The session should be deleted only if the session is entirely empty if settings.SESSION_COOKIE_NAME in request.COOKIES and empty: response.delete_cookie( settings.SESSION_COOKIE_NAME, path=settings.SESSION_COOKIE_PATH, domain=settings.SESSION_COOKIE_DOMAIN, ) else: if accessed: patch_vary_headers(response, ('Cookie',)) if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) # Save the session data and refresh the client cookie. # Skip session save for 500 responses, refs #3881. if response.status_code != 500: try: request.session.save() except UpdateError: raise SuspiciousOperation( "The request's session was deleted before the " "request completed. The user may have logged " "out in a concurrent request, for example." ) response.set_cookie( settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None, ) return response
首先定义了三个变量
若是执行了上面视图函数中的操做,那么accessed和modified应该都是True
is_empty()执行的代码以下
从前面的代码能够看到咱们的self._session其实就是_session_cache,而咱们给他作了赋值,全部这里的empty是False
接着往下走
前面的赋值操做未出现异常咱们执行else后的if判断,因为empty为False,因此执行else后的代码
这里能够看到其实就是定义了session的过时时间等相关的属性
接着,当后台运行没错,状态码不是500时,咱们执行request.session.save(),这里save具体作了什么呢
首先判断self.session_key是否为None,若是是第一次访问则为None,执行self.create()
这个方法里首先用self._get_new_session_key()方法生成了一个随机字符串赋值给self._session_key,而后继续执行self.save方法,而且设置must_create=True
这时再进入save方法,设置data = self._get_session(no_load=must_create),self._get_session方法执的结果其实就是上面的self._session_cache,就是咱们设置的有键值对的字典
因此data的值就是咱们设置的保存用户信息的字典
而后执行obj = self.create_model_instance(data),self.create_model_instance(data)执行下面的代码
其实就是返回了一个包含session_key,session_data等字段的model对象
而后调用事务,将数据保存到数据库
这里第一次访问时,must_create是True,因此是添加操做,而当后面再访问时,must_create是False,因此执行的是更新操做
数据保存完成后,咱们再用response.set_cookie设置了COOKIE值,最后将结果返回