Django - AuthenticationMiddleware 设置 request.user

3 投票
1 回答
2924 浏览
提问于 2025-04-17 17:40


关于 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_requestLazyUser() 赋值给类级别的 user 属性,这对我来说基本上意味着两件事:

  • HttpRequest 类(request.__class__)在两个请求之间保存了它的 user 属性,因此后续的 request 对象可以访问它。
  • 每当一个视图函数尝试访问 request.user 时,LazyUser 对象的 __get__ 方法就会被触发,并返回一个用户对象,这个对象可能来自请求的缓存或认证存储。

我这样理解对吗?

另外,我注意到在 1.4 中有两个主要的变化:

  • SimpleLazyObject 被赋值给 request,而不是它的类(所以它是一个实例属性)。
  • LazyObjectSimpleLazyObject 并没有定义(自定义)它们自己的 __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的会话中间件。

撰写回答