jango.contrib.sessions-SessionBase

来源:互联网 发布:小学生专用直播软件 编辑:程序博客网 时间:2024/06/02 00:34


摘要 上篇说了django sessions模块的处理流程。session-data的数据管理,都是由一个类负责。这个基类是SessionBase,我们可以继承SessionBase,实现自己对session-data的管理。

SessionBase之所以可当作字典来操作,因为它本身就是对字典的包装。所以需要了解一下python的一些魔法方法。


举个例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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__负责改变数据。

__delitem__负责删除数据。

__contains__负责判断是否包含这个key。


然后看SessionBase的定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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的其他的方法。

基本上都是_session的包装。


现在来看看_session的定义:

?
1
_session = property(_get_session)

_session的值是_get_session方法返回的。


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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。



?
1
2
3
4
5
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为空。

?
1
2
3
4
5
6
7
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里。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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。

?
1
2
3
4
5
6
7
8
9
10
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


0 0
原创粉丝点击