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