django: Purpose of django.utils.functional.SimpleLazyObject?

泄露秘密 提交于 2019-12-17 08:30:35

问题


I ran into an issue where I assigned request.user to a variable called prior_user, then essentially authenticated the user, then checked to see if request.user != prior_user. I expected them not to be the same and that prior_user should contain `AnonymousUser. To my surprise, they were the same.

Sample code:

prior_user = request.user   # request object, obtained froma  view
authenticate_user(request)   # some function that authenticates
print prior_user.username != request.user.username   # returns False i.e.they are the same!

I then discovered prior_user actually contains an instance of django.utils.functional.SimpleLazyObject so I assume it is some sort of lazy lookup type thing i.e. prior_user's value isn't looked up until actually used. Looking at the source code, I cannot confirm this.

Anyone with django experience can tell me what is going on and why it is needed?

This leaves me a little shaken, because the usual assignment statement doesn't work the way I expect and what else within Django acts like this? Nor did I see this described in the docs.

So anyone with super human knowledge of django can provide some clarity?


回答1:


The auth middleware adds a user attribute to request that is an instance of SimpleLazyObject. SimpleLazyObject, itself is a subclass of LazyObject. LazyObject is, as described by the actual code:

A wrapper for another class that can be used to delay instantiation of the wrapped class

SimpleLazyObject merely sets that class (the _wrapped attribute on LazyObject) via a passed in method, in this case, get_user. Here's the code for that method:

def get_user(request):
    if not hasattr(request, '_cached_user'):
        request._cached_user = auth.get_user(request)
    return request._cached_user

That in itself is really just a wrapper around auth.get_user, that enables a sort of caching mechanism. So here's what actually is eventually run:

def get_user(request):
    from django.contrib.auth.models import AnonymousUser
    try:
        user_id = request.session[SESSION_KEY]
        backend_path = request.session[BACKEND_SESSION_KEY]
        backend = load_backend(backend_path)
        user = backend.get_user(user_id) or AnonymousUser()
    except KeyError:
        user = AnonymousUser()
    return user

So, all that's really going on here is that request.user is ambiguous until it's actually used for something. This is important, because it allows it to adapt depending on the current authentication status. If you access a property on it before you authenticate, it returns an instance AnonymousUser, but if you authenticate and then access it, it returns an instance of User.



来源:https://stackoverflow.com/questions/10506766/django-purpose-of-django-utils-functional-simplelazyobject

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!