Django - AuthenticationMiddleware 设置 request.user
关于 AuthenticationMiddleware
,为什么 Django 1.3 在类级别处理 user
属性,而在 1.4 中又改成了实例属性呢?
这是 1.3 的内容
class LazyUser(object):
def __get__(self, request, obj_type=None):
if not hasattr(request, '_cached_user'):
from django.contrib.auth import get_user
request._cached_user = get_user(request)
return request._cached_user
class AuthenticationMiddleware(object):
def process_request(self, request):
request.__class__.user = LazyUser()
return None
这是 1.4 的内容
def get_user(request):
if not hasattr(request, '_cached_user'):
request._cached_user = auth.get_user(request)
return request._cached_user
class AuthenticationMiddleware(object):
def process_request(self, request):
assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.user = SimpleLazyObject(lambda: get_user(request))
# SimpleLazyObject inherits from LazyObject
在 1.3 中,我理解 process_request
将 LazyUser()
赋值给类级别的 user
属性,这对我来说基本上意味着两件事:
HttpRequest
类(request.__class__
)在两个请求之间保存了它的user
属性,因此后续的request
对象可以访问它。- 每当一个视图函数尝试访问
request.user
时,LazyUser
对象的__get__
方法就会被触发,并返回一个用户对象,这个对象可能来自请求的缓存或认证存储。
我这样理解对吗?
另外,我注意到在 1.4 中有两个主要的变化:
SimpleLazyObject
被赋值给request
,而不是它的类(所以它是一个实例属性)。LazyObject
和SimpleLazyObject
并没有定义(自定义)它们自己的__get__
方法。
这样一来,get_user
是什么时候被触发的呢?
现在 AuthenticationMiddleware
是如何在两个请求之间存储 request.user 的,并且如何覆盖 Http 的无状态性呢?
1 个回答
2
不,这两个版本是一样的。不过1.4版本更简单一些。
以前是怎么工作的
LazyUser
对象实现了一个叫做描述符协议的东西。
描述符有点复杂,但大致的意思是,虽然user
是一个类的属性,但当你访问request.user
时,实际上会调用request.__class__.user.__get__(request)
,这样就能让__get__
方法访问请求的参数,最终返回与请求绑定的用户。
现在是怎么工作的
现在user
属性使用了SimpleLazyObject
这个结构来实现同样的目的:如果不需要,就避免加载所有用户相关的内容。
至于get_user
什么时候被调用:
当你访问request.user
上的某个属性,比如request.user.attr1
时,实际上会调用request.user.__getattr__('attr1')
,然后这又会调用request.user._setup()
,最终会调用get_user
。
Django是如何创建状态的
通过使用会话(Sessions)。可以看看Django的会话中间件。