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值,最後將結果返回