Reputation:
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:
HttpRequest
class (request.__class__
) stored its user
attribute between two requests, so future request
objects had access to it.request.user
, the LazyUser
object's __get__
method was triggered and returned a user object, either from the request's cache or from auth storage. Am I correct about it?
Also, I have noticed in 1.4 these two major changes:
SimpleLazyObject
is assigned to request
, not to its class (so, it is an instance property).LazyObject
and SimpleLazyObject
don't define (customize) their own __get__
method. 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
Reputation: 55199
No. The two versions are equivalent. The 1.4 version is simpler, though.
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.
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
.
Through the use of Sessions. Have a look at django's session middleware.
Upvotes: 2