user1563285
user1563285

Reputation:

Django - AuthenticationMiddleware setting request.user


Regarding AuthenticationMiddleware, why did Django 1.3 handle the user property at class level, and why was it changed to an instance property in 1.4?


This is from 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


And this from 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


In 1.3, I understood that process_request assigned LazyUser() to the class level user attribute, which to me basically means two things:

Am I correct about it?

Also, I have noticed in 1.4 these two major changes:

This way, when is get_user triggered?
How does AuthenticationMiddleware now store request.user between two requests, and override the statelessness of Http?

Upvotes: 3

Views: 3007

Answers (1)

Thomas Orozco
Thomas Orozco

Reputation: 55199

No. The two versions are equivalent. The 1.4 version is simpler, though.

How it used to work

The LazyUser object implemented the descriptor protocol.

Descriptors are a bit convoluted to understand, but the general idea here is that although user was a class attribute, accessing request.user woud call request.__class__.user.__get__(request), and therefore let the __get__ method access the request parameters, which it would use to return the user bound to the request.

How it works now

The user property uses the SimpeLazyObject construct to achieve the same goal: avoid loading all the user machinery if it's not going to be needed.

As to when get_user is called:

When you access an attribute on request.user, for example request.user.attr1, then request.user.__getattr__('attr1') will be called, which will in turn call request.user._setup(), which will eventually call get_user.

How Django creates statefulness

Through the use of Sessions. Have a look at django's session middleware.

Upvotes: 2

Related Questions