SessionBase之因此可看成字典来操做,由于它自己就是对字典的包装。因此须要了解一下python的一些魔法方法。python
举个例子:浏览器
class DictWrapper: def __init__(self): self.dict = {} def __getitem__(self, key): return self.dict[key] def __setitem__(self, key, value): self.dict[key] = value def __delitem__(self, key): del self.dict[key] def __contains__(self, key): return key in self._session
__getitem__ 负责获取数据。 缓存
__setitem__负责改变数据。cookie
__delitem__负责删除数据。session
__contains__负责判断是否包含这个key。app
而后看SessionBase的定义:
less
class SessionBase(object): """ Base class for all Session classes. """ TEST_COOKIE_NAME = 'testcookie' TEST_COOKIE_VALUE = 'worked' def __init__(self, session_key=None): self._session_key = session_key self.accessed = False self.modified = False self.serializer = import_string(settings.SESSION_SERIALIZER) def __contains__(self, key): return key in self._session def __getitem__(self, key): return self._session[key] def __setitem__(self, key, value): self._session[key] = value self.modified = True def __delitem__(self, key): del self._session[key] self.modified = True def get(self, key, default=None): return self._session.get(key, default) def pop(self, key, *args): self.modified = self.modified or key in self._session return self._session.pop(key, *args) def update(self, dict_): self._session.update(dict_) self.modified = True def has_key(self, key): return key in self._session def keys(self): return self._session.keys() def values(self): return self._session.values() def items(self): return self._session.items() def iterkeys(self): return self._session.iterkeys() def itervalues(self): return self._session.itervalues() def iteritems(self): return self._session.iteritems()
除了上述几个魔法方法, SessionBase还实现了dict的其余的方法。ide
基本上都是_session的包装。函数
如今来看看_session的定义:性能
_session = property(_get_session)
_session的值是_get_session方法返回的。
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 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
_get_session方法会优先去获取_session_cache这个缓存变量的值,若是没有则调用load方法。
注意self.accessed属性的改变。它会记录是否获取过session。
def load(self): """ Loads the session data and returns a dictionary. """ raise NotImplementedError('subclasses of SessionBase must provide a load() method')
load方法须要子类定义,返回session-data。
通常load实现要注意这种状况,用户第一次登录是没有_session_cache。注意_get_session方法,它会经过捕获AttributeError异常,判断是否存在_session_cache。若是没有会调用load方法。
因此当用户没有_session_cache的时候,须要返回一个空字典。
注意一下clear的实现。由于执行clear函数时,若是self._session有可能会调用load函数,致使没必要要的性能开销。
因此直接复制_session_cache为空。
def clear(self): # To avoid unnecessary persistent storage accesses, we set up the # internals directly (loading data wastes time, since we are going to # set it to an empty dict anyway). self._session_cache = {} self.accessed = True self.modified = True
由于session和cookie会有一个有效期,以'_session_expiry'存在_session_data里。
def get_expiry_date(self, **kwargs): """Get session the expiry date (as a datetime object). Optionally, this function accepts `modification` and `expiry` keyword arguments specifying the modification and expiry of the session. """ try: modification = kwargs['modification'] except KeyError: modification = timezone.now() # Same comment as in get_expiry_age try: expiry = kwargs['expiry'] except KeyError: expiry = self.get('_session_expiry') if isinstance(expiry, datetime): return expiry if not expiry: # Checks both None and 0 cases expiry = settings.SESSION_COOKIE_AGE return modification + timedelta(seconds=expiry)
这里注意_session_expiry对应的值,多是为int,也多是datetime类型。若是为int,则表示剩下的有效期,以second为单位。若是为datetime类型,则为有效日期,须要计算二者的时间差,也是以second为单位。
get_expire_at_browser_close方法用来判断session的截至时间是否为关闭浏览器的时间。
当_session_expiry为None而且settings.SESSION_EXPIRE_AT_BROWSER_CLOSE设置为true,
当_session_expiry为0,
都会返回true。
def get_expire_at_browser_close(self): """ Returns ``True`` if the session is set to expire when the browser closes, and ``False`` if there's an expiry date. Use ``get_expiry_date()`` or ``get_expiry_age()`` to find the actual expiry date/age, if there is one. """ if self.get('_session_expiry') is None: return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE return self.get('_session_expiry') == 0