先看auth中间件的代码,按照惯例,先执行process_request函数的代码。assert断言语句主要是判断,session中间件是不是存在,而且是不是在auth中间件的前面(谁在前面谁先执行,auth中间要凭借是否有之前登录的session去判断是否是登录过的用户)。session中间件一般都会默认打开的,所以下一步执行request.user = SimpleLazyObject(lambda: get_user(request))这段代码,“(lambda: get_user(request)”这个参数可以先理解为实际的 User 对象(相当于一个func,而不是func(),是一个地址,见下面第一小案例,相当于调用函数后,可以获取当前用户的模型对象),暂时忽略。我们之前访问一个登录用户的信息就是通过“request.user.要访问的属性名”去访问登录用户的信息的。
#这段代码和本文关系不大,只是举例
#这个p只是一个函数地址
p = lambda x,y:x+y
print(p(4,6))
def get_user(request):
#如果缓存中没有这个请求用户的信息
if not hasattr(request, '_cached_user'):
request._cached_user = auth.get_user(request)
return request._cached_user
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_user(request))
事实上,request.user只是SimpleLazyObject的一个实例对象而已,那SimpleLazyObject做了什么操作呢?上代码:
class SimpleLazyObject(LazyObject):
def __init__(self, func):
self.__dict__['_setupfunc'] = func
super().__init__()
def _setup(self):
self._wrapped = self._setupfunc()
#其他函数的代码先暂时忽略。。。
从上图可以看到,先是继承了LazyObject类,先不管它,实例化了SimpleLazyObject类后,会自动调用 init__()函数,并传入一个参数func(这里可以先理解为当前登录的对象,或者说是地址),然后把这个参数赋值给了LazyObject类的一个变量_setupfunc,然后调用父类的__init__保证不会漏掉父类的某些操作导致程序不能运行。
从上面的分析中,似乎没发现调用_setup()函数的操作,那_setup()是什么时候调用的呢?
当我们通过request.user.某个属性的时候调用(相当于SimpleLazyObject(lambda: get_user(request)).某个属性)。那是怎么调用的呢?
当访问一个类的属性的时候,会触发_getattr_()方法,在此代码中即SimpleLazyObject.__getattr__()。很显然SimpleLazyObject类中没有定义这个方法,那就去父类LazyObject中寻找:
class LazyObject:
_wrapped = None
def __init__(self):
self._wrapped = empty #empty = object()
__getattr__ = new_method_proxy(getattr)
def __setattr__(self, name, value):
if name == "_wrapped":
self.__dict__["_wrapped"] = value
else:
if self._wrapped is empty:
self._setup()
setattr(self._wrapped, name, value)
def __delattr__(self, name):
if name == "_wrapped":
raise TypeError("can't delete _wrapped.")
if self._wrapped is empty:
self._setup()
delattr(self._wrapped, name)
def _setup(self):
"""
Must be implemented by subclasses to initialize the wrapped object.
"""
raise NotImplementedError('subclasses of LazyObject must provide a _setup() method')
def __reduce__(self):
if self._wrapped is empty:
self._setup()
return (unpickle_lazyobject, (self._wrapped,))
def __copy__(self):
if self._wrapped is empty:
# If uninitialized, copy the wrapper. Use type(self), not
# self.__class__, because the latter is proxied.
return type(self)()
else:
# If initialized, return a copy of the wrapped object.
return copy.copy(self._wrapped)
def __deepcopy__(self, memo):
if self._wrapped is empty:
result = type(self)()
memo[id(self)] = result
return result
return copy.deepcopy(self._wrapped, memo)
__bytes__ = new_method_proxy(bytes)
__str__ = new_method_proxy(str)
__bool__ = new_method_proxy(bool)
__dir__ = new_method_proxy(dir)
__class__ = property(new_method_proxy(operator.attrgetter("__class__")))
__eq__ = new_method_proxy(operator.eq)
__lt__ = new_method_proxy(operator.lt)
__gt__ = new_method_proxy(operator.gt)
__ne__ = new_method_proxy(operator.ne)
__hash__ = new_method_proxy(hash)
__getitem__ = new_method_proxy(operator.getitem)
__setitem__ = new_method_proxy(operator.setitem)
__delitem__ = new_method_proxy(operator.delitem)
__iter__ = new_method_proxy(iter)
__len__ = new_method_proxy(len)
__contains__ = new_method_proxy(operator.contains)
限定为到 getattr = new_method_proxy(getattr)这句代码,可以看出并没有直接写成函数的形式,这里展现的只是一个函数变量,猜测应该和闭包有关。点进去看一下:
empty = object()
def new_method_proxy(func):
def inner(self, *args):
if self._wrapped is empty:
self._setup()
return func(self._wrapped, *args)
return inner
从上图代码中可以看出,确实是这样,此函数返回的是inner(内层函数的函数变量,只是函数的一个地址),当我们调用 getattr()函数时,对应的才能把return inner(),去调用内层函数。
前面说过,访问一个类中的实例变量会调用 getattr(),根据闭包的原理,又会去调inner()函数,接下来判断self._wrapped is empty是否为空,如果时通过reques.user第一次访问某个变量时,self._wrapped确实为empty,见下面代码:
class LazyObject:
_wrapped = None
def __init__(self):
self._wrapped = empty #empty = object()
如果当第一次通过request.user.属性去访问当前用户的某个属性的时候, self._wrapped is empty的条件是成立的,接下来就接着执行self._setup()这句代码。_setup()函数子类中是有的,所以直接从子类中找:
def _setup(self):
self._wrapped = self._setupfunc()
从代码中可以看出,先执行_setupfunc()函数再赋值给self._wrapped,然后就改变了self._wrapped了的状态,self._setupfunc其实就是前面的func,即lambda: get_user(request)这个函数变量(也可以理解为user的模型对象,通过它就可以访问当前用户的属性信息了)。赋值完成后,self._wrapped就不再是empty了。
下面的代码第二次再通过request.user.属性取值的时候就不会进行调用self._setup(),原理很简单,再次通过request.user.属性取值时,代码执行过程依然会和之前一样,先走到if self._wrapped is empty这句代码:
def new_method_proxy(func):
def inner(self, *args):
if self._wrapped is empty:
self._setup()
return func(self._wrapped, *args)
return inner
会进行判断 self._wrapped 是不是 empty,很明显self._wrapped = self._setupfunc()了,
然后执行传入的func(self._wrapped, *args)方法,这个func(self._wrapped, *args)其实就是getattr()方法,然后你想获取当前用户的那个属性,getattr就可以帮你获取当前用户的哪个属性了,然后再由函数一层层返回,返回到request.user.你要访问的属性。
参考:https://blog.csdn.net/u011019726/article/details/79174251