我是使用的pyCharm查看的源码,先是用pyCharm生成了一个django项目,在settings文件中中间件都是利用字符串的形式引用的
我们可以把字符串复制黏贴下来,然后把两边引号去掉用导入的方式导入该中间件,这样我们就可以用ctrl+左键的方式开始查看中间件的源码了。
进入中间件 我们可以看到
__init__
先是进行初始化,然后又两个方法。
先看第一句
self.get_response = get_response
这里是一个赋值默认赋为None
看第二句我们可以进入 settings.SESSION_ENGINE的settings看看这个是个什么东西,进入下一个py文件
from django.conf import global_settings from django.core.exceptions import ImproperlyConfigured from django.utils.functional import LazyObject, empty
我们可以看到这个py文件中导入了一个global_settings的文件,继续点开我们可以在该文件中看到如下代码
SESSION_ENGINE = \'django.contrib.sessions.backends.db\'
这是一个字符串的变量我们可以看出这是一个类似数据库的东西,而源码中执行的第二行代码 import_model是字符串导入模块的方式,那么我们可以知道这个settings.SESSION_ENGINE应该是一个模块
我们用和导入中间件一样的方式导入这个模块进入其中可以看到
这个SessionStore是一个类
实例化中的三句代码已经解释清楚
process_request
接下来我们看
SessionMiddleware中间件 def process_request(self, request): session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME) request.session = self.SessionStore(session_key)
我们进入COOKIES可以看到COOKIES是一个空的字典(当然这是第一次请求的时候),所以第一次取值时session_key应该是一个空值。
def _set_session_key(self, value): """ Validate session key on assignment. Invalid values will set to None. """ if self._validate_session_key(value): self.__session_key = value else: self.__session_key = None session_key = property(_get_session_key) _session_key = property(_get_session_key, _set_session_key) def _get_session(self, no_load=False): """ Lazily loads session from storage (unless "no_load" is True, when only an empty dict is stored) and stores it in the current instance. """ self.accessed = True # accessed设置为True try: return self._session_cache # 第一次进来会报错因为没有设置该属性 except AttributeError: if self.session_key is None or no_load: self._session_cache = {} # 此时设置self._session_cache = {}
else: self._session_cache = self.load()
return self._session_cache _session = property(_get_session)
此时session初始化结束
接着第二句我们可以看到session是一个对象
process_response
接着第三个函数
1 def process_response(self, request, response): 2 """ 3 If request.session was modified, or if the configuration is to save the 4 session every time, save the changes and set a session cookie or delete 5 the session cookie if the session has been emptied. 6 """ 7 try: 8 accessed = request.session.accessed 9 modified = request.session.modified 10 empty = request.session.is_empty() 11 except AttributeError: 12 pass 13 else: 14 # First check if we need to delete this cookie. 15 # The session should be deleted only if the session is entirely empty 16 if settings.SESSION_COOKIE_NAME in request.COOKIES and empty: # 删除session进行的操作 17 response.delete_cookie( 18 settings.SESSION_COOKIE_NAME, 19 path=settings.SESSION_COOKIE_PATH, 20 domain=settings.SESSION_COOKIE_DOMAIN, 21 ) 22 else: 23 if accessed: 24 patch_vary_headers(response, (\'Cookie\',)) 25 if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: 26 if request.session.get_expire_at_browser_close(): 27 max_age = None 28 expires = None 29 else: 30 max_age = request.session.get_expiry_age() 31 expires_time = time.time() + max_age 32 expires = cookie_date(expires_time) 33 # Save the session data and refresh the client cookie. 34 # Skip session save for 500 responses, refs #3881. 35 if response.status_code != 500: 36 try: 37 request.session.save() 38 except UpdateError: 39 raise SuspiciousOperation( 40 "The request\'s session was deleted before the " 41 "request completed. The user may have logged " 42 "out in a concurrent request, for example." 43 ) 44 response.set_cookie( 45 settings.SESSION_COOKIE_NAME, 46 request.session.session_key, max_age=max_age, 47 expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, 48 path=settings.SESSION_COOKIE_PATH, 49 secure=settings.SESSION_COOKIE_SECURE or None, 50 httponly=settings.SESSION_COOKIE_HTTPONLY or None, 51 ) 52 return response
先看request.session.accessed,modified = request.session.modified是什么
class SessionBase(object): """ Base class for all Session classes. """ TEST_COOKIE_NAME = \'testcookie\' TEST_COOKIE_VALUE = \'worked\' __not_given = object() def __init__(self, session_key=None): self._session_key = session_key self.accessed = False # 该值默认为False self.modified = False self.serializer = import_string(settings.SESSION_SERIALIZER)
def __setitem__(self, key, value):
self._session[key] = value # 当我们进行 obj[\'key\'] = value
self.modified = True
def __delitem__(self, key):
del self._session[key] # 当我们进行删除时 操作都会使 modeifed改变
self.modified = True
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 except AttributeError: return True
如果有session_key或者session_cache中有值那么久返回False。
我们接下来直接看 if response.status_code != 500: 往后的这一部分request.session.save() 因为request.session是一个SessionStroe对象所以save在对象中
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
第一次进来self.session值就是None执行self.create(),如果不是第一次执行那么就有session值,就不进行create()操作
1 def create(self): 2 while True: 3 self._session_key = self._get_new_session_key() 4 try: 5 # Save immediately to ensure we have a unique entry in the 6 # database. 7 self.save(must_create=True) # 这里的must_save = Ture (def save(self, must_create=False):) must_create()默认为False,即有了session后不执行create那么must_create 就是False 8 except CreateError: 9 # Key wasn\'t unique. Try again. 10 continue 11 self.modified = True 12 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(), ) 保存到数据库
with transaction.atomic(using=using): obj.save(force_insert=must_create, force_update=not must_create, using=using)
obj.save(force_insert=must_create, force_update=not must_create, using=using)
是插入数据还是更新数据取决于must_create
暂时先写到这里