settings.py

MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
]

1. 看看SessionMiddleware类   from django.contrib.sessions.middleware import SessionMiddleware

class SessionMiddleware(MiddlewareMixin):
   #1.1
def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
   #2
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

1.1步:每个中间件的类在调用的时候都会先执行init 构造方法

class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
#1.1.1 到配置文件中获取一个类
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore

1.1.1步:django自带的settings中没有SESSION_ENGINE这个属性,那就需要去全局的global_settings文件中找

        SESSION_ENGINE = 'django.contrib.sessions.backends.db'     #这个时候self.SessionStore =db 文件中的 SessionStore类
class SessionStore(SessionBase):
"""
Implements database session store.
"""
def __init__(self, session_key=None):
super(SessionStore, self).__init__(session_key) @classmethod
def get_model_class(cls):
# Avoids a circular import and allows importing SessionStore when
# django.contrib.sessions is not in INSTALLED_APPS.
from django.contrib.sessions.models import Session
return Session @cached_property
def model(self):
return self.get_model_class() def load(self):
try:
s = self.model.objects.get(
session_key=self.session_key,
expire_date__gt=timezone.now()
)
return self.decode(s.session_data)
except (self.model.DoesNotExist, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
logger.warning(force_text(e))
self._session_key = None
return {} def exists(self, session_key):
return self.model.objects.filter(session_key=session_key).exists() def create(self):
while True:
self._session_key = self._get_new_session_key()
try:
# Save immediately to ensure we have a unique entry in the
# database.
self.save(must_create=True)
except CreateError:
# Key wasn't unique. Try again.
continue
self.modified = True
return def create_model_instance(self, data):
"""
Return a new instance of the session model object, which represents the
current session state. Intended to be used for saving the session data
to the database.
"""
return self.model(
session_key=self._get_or_create_session_key(),
session_data=self.encode(data),
expire_date=self.get_expiry_date(),
) def save(self, must_create=False):
"""
Saves the current session data to the database. If 'must_create' is
True, a database error will be raised if the saving operation doesn't
create a *new* entry (as opposed to possibly updating an existing
entry).
"""
if self.session_key is None:
return self.create()
data = self._get_session(no_load=must_create)
obj = self.create_model_instance(data)
using = router.db_for_write(self.model, instance=obj)
try:
with transaction.atomic(using=using):
obj.save(force_insert=must_create, force_update=not must_create, using=using)
except IntegrityError:
if must_create:
raise CreateError
raise
except DatabaseError:
if not must_create:
raise UpdateError
raise def delete(self, session_key=None):
if session_key is None:
if self.session_key is None:
return
session_key = self.session_key
try:
self.model.objects.get(session_key=session_key).delete()
except self.model.DoesNotExist:
pass @classmethod
def clear_expired(cls):
cls.get_model_class().objects.filter(expire_date__lt=timezone.now()).delete()

SessionStore类

2.这时候就该走中间件的process_request方法了

    def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME) #从cookies中获取 'sessionid' 对应的值
request.session = self.SessionStore(session_key) #把获取的值给db中的SessionStore类进行实例化并赋值给request.session
class SessionStore(SessionBase):
def __init__(self, session_key=None):
super(SessionStore, self).__init__(session_key) #调用父类的 init 构造方
class SessionBase(object):
   session_key = property(_get_session_key)
   _session_key = property(_get_session_key, _set_session_key) #在代码加载的时候要类的字段在方法前面加载,这时绑定了property方法,如果是获取操作就走_get_session_key方法,设置操作就走_set_session_key方法

   def __init__(self, session_key=None):
     #2.1
self._session_key = session_key #给_session_key赋值,走_set_session_key方法,把session_key传进去
self.accessed = False
self.modified = False
self.serializer = import_string(settings.SESSION_SERIALIZER) #SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'
     #表示 django 的session中间件是用Json进行序列化

2.1步:

class SessionBase(object):
def _set_session_key(self, value): if self._validate_session_key(value): #value = None
self.__session_key = value
else:
self.__session_key = None def _validate_session_key(self, key):
#如果sessionid有值并且长度大于等于8
return key and len(key) >= 8

3. 然后该走视图中 对request.session进行操作,如果对session就行设置 值就执行 SessionStore 类中的__setitem__方法,如果是取session中的值就执行 __getitem__方法,删除执行__delitem__方法

,但是在SessionStore类中没有发现这个方法,那就去它的父类中找

class SessionBase(object):
   #self 是 request.session 这个SessionBase类对象
def __getitem__(self, key):
return self._session[key] #到字典中获取值 def __setitem__(self, key, value):
self._session[key] = value #给字典设置值,并且改变modified 状态为 True
self.modified = True def __delitem__(self, key):
del self._session[key] #删除字典中的键值对,并且改变modified 状态为 True
self.modified = True    

在上面的代码中,我们看到self._session,点进去看看

class SessionBase(object):
_session = property(_get_session)
class SessionBase(object):
   #self 是 request.session 这个SessionBase类对象
 
def _get_session(self, no_load=False): self.accessed = True #在这步给session设置值的时候 把这个accessed 状态改成了 True
try:
return self._session_cache # 获取self 的_session_cache 属性,如果没有就走下面的except方法
except AttributeError:
if self.session_key is None or no_load:
self._session_cache = {} #赋值操作
else:
self._session_cache = self.load()
return self._session_cache

4. 走中间件的process_response 方法

class SessionMiddleware(MiddlewareMixin):
def process_response(self, request, response): try:
accessed = request.session.accessed # TRUE
modified = request.session.modified #当设置或删除操作时 为TRUE
  
       #4.1
empty = request.session.is_empty() # Flase
except AttributeError:
pass
else:
# 4.2 如果sessionid在cookies中 并且值为空,从cookie中把sessionid键值删除
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',))
          4.3 有效期和 过期时间相关
if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: #True and True
            #在浏览器关闭的时候 session 的有效期为 None , 过期时间 为 None
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:
                 #4.4 访问正常
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."
)
               #4.5 对 response 设置 cookie
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

4.1步:

class SessionBase(object):
def is_empty(self):
"Returns True when there is no session_key and the session is empty"
try:
return not bool(self._session_key) and not self._session_cache # 获取_session_key 执行property(_get_session_key)方法
                                              # 此时 self._session_cache 中已经有值了
        # True and Flase
except AttributeError:
return True
class SessionBase(object):
def _get_session_key(self):
return self.__session_key #从2.1步可以得出 为None

4.4步:

class SessionStore(SessionBase):
def save(self, must_create=False):
     #4.4.1
if self.session_key is None: return self.create() data = self._get_session(no_load=must_create)
obj = self.create_model_instance(data)
using = router.db_for_write(self.model, instance=obj)
try:
with transaction.atomic(using=using):
obj.save(force_insert=must_create, force_update=not must_create, using=using)
except IntegrityError:
if must_create:
raise CreateError
raise
except DatabaseError:
if not must_create:
raise UpdateError
raise

4.4.1步:

#session_key 获取,执行session_key = property(_get_session_key)  _get 方法

class SessionBase(object):
def _get_session_key(self):
return self.__session_key # None

执行 self.create()  方法

class SessionStore(SessionBase):
def create(self):
while True:
       #4.4.1.1
self._session_key = self._get_new_session_key() #对_session_key 赋值操作,执行_set 方法
try:
          #4.4.1.2 传参 must_create=True
self.save(must_create=True)
except CreateError:
# Key wasn't unique. Try again.
continue
self.modified = True
return

4.4.1.1步:

class SessionBase(object):
def _get_new_session_key(self):
while True:
session_key = get_random_string(32, VALID_KEY_CHARS)
if not self.exists(session_key):
break
return session_key #随机字符串
class SessionBase(object):
def _set_session_key(self, value): if self._validate_session_key(value): #此时 value 是一个随机字符串
self.__session_key = value #self.__session_key 是 一个随机字符串
else:
self.__session_key = None

4.4.1.2步:

class SessionStore(SessionBase):
def save(self, must_create=False): if self.session_key is None: #获取session_key 操作,执行_get方法 见下面
return self.create()
data = self._get_session(no_load=must_create) #must_create =True 见下面
obj = self.create_model_instance(data) #django创建session表对象
using = router.db_for_write(self.model, instance=obj)
try:
with transaction.atomic(using=using):
          # session对象 执行save方法 参数must_create = True 表示是创建 一条数据
obj.save(force_insert=must_create, force_update=not must_create, using=using)
except IntegrityError:
if must_create:
raise CreateError
raise
except DatabaseError:
if not must_create:
raise UpdateError
raise class SessionBase(object): session_key = property(_get_session_key) def _get_session_key(self):
return self.__session_key #此时是一个随机字符串 class SessionBase(object):
def _get_session(self, no_load=False): self.accessed = True
try:
return self._session_cache #此时 字典中已经有值
except AttributeError:
if self.session_key is None or no_load:
self._session_cache = {}
else:
self._session_cache = self.load()
return self._session_cache

python-django中间件session源码的更多相关文章

  1. Django中间件部分源码分析

    中间件源码分析 中间件简介 中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Django的输入和输出.每个中间件组件都负责做一些特定的 ...

  2. Django中间件CsrfViewMiddleware源码分析

    Django Documentation csrf保护基于以下: 1, 一个CSRF cookie基于一个随机生成的值,其他网站无法得到,次cookie有CsrfViewMiddleware产生.它与 ...

  3. django中间件CsrfViewMiddleware源码分析,探究csrf实现

    Django Documentation csrf保护基于以下: 1. 一个CSRF cookie 基于一个随机生成的值,其他网站无法得到.此cookie由CsrfViewMiddleware产生.它 ...

  4. Django session 源码流程

    流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...

  5. Django——Session源码分析

    首先我们导入django.contrib.sessions.middleware这个中间件,查看里面的Session源码 from django.contrib.sessions.middleware ...

  6. Flask框架(三)—— 请求扩展、中间件、蓝图、session源码分析

    Flask框架(三)—— 请求扩展.中间件.蓝图.session源码分析 目录 请求扩展.中间件.蓝图.session源码分析 一.请求扩展 1.before_request 2.after_requ ...

  7. django python mange.py runserver 源码

    django python mange.py runserver 源码 入 口 mange.py文件 execute_from_command_line函数 输入参数为['manage.py', 'r ...

  8. 跨站请求伪造(csrf),django的settings源码剖析,django的auth模块

    目录 一.跨站请求伪造(csrf) 1. 什么是csrf 2. 钓鱼网站原理 3. 如何解决csrf (1)思路: (2)实现方法 (3)实现的具体代码 3. csrf相关的装饰器 (1)csrf_p ...

  9. Django搭建及源码分析(三)---+uWSGI+nginx

    每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...

随机推荐

  1. 使用closest替换parent

    尽量不要使用parent去获取DOM元素,如下代码: var $activeRows = $this.parent().parent().children(".active"); ...

  2. facebook api之Access Tokens之Business Manager System User

    Business Manager System User Make programatic, automated actions on ad objects or Pages, or do progr ...

  3. HDU 5976 Detachment(拆分)

    HDU 5976 Detachment(拆分) 00 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)   Problem D ...

  4. 转入Python3.5

    Future 我决定从python2.7转到python3.5,毕竟python3才是未来,业余程序员也是有追求的 嵌入发布 版本3.5中的新特性.可以将python嵌入用户程序,变成程序的一部分,随 ...

  5. 51nod 1378 夹克老爷的愤怒(树型dp+贪心)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 题意: 思路:要想放得少,尽量放在叶子节点处,叶子节点处点比较多. ...

  6. jQuery页面加载初始化常用的三种方法

    当页面打开时我们需要执行一些操作,这个时候如果我们选择使用jquery的话,需要重写他的3中方法,自我感觉没什么区 别,看个人喜好了,第二种感觉比较简单明了: 第一种: 复制代码代码如下: <s ...

  7. C# 获取程序运行目录

    string a = "BaseDirectory:" + AppDomain.CurrentDomain.BaseDirectory + "\r\n" + & ...

  8. 【BZOJ】2331: [SCOI2011]地板

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2331 一眼插头DP... 考虑一个L形的东西,要构成它可以划分为两个阶段,即当前线段是拐了 ...

  9. bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 16294  Solved: 6645[Submit ...

  10. C#端加载数据库,Combobox与Node控件绑定数据源demo示例

    最近一直在做网页.用的js比较多,最近需要做一个C#相关的demo,一开始还有点不适应,写了几句有点感觉了 本篇博客的主要内容是C#怎么读取数据库文件里的数据以及相关控件如何绑定数据源,所做的Demo ...