Vraag django: Doel van django.utils.functional.SimpleLazyObject?


Ik kwam een ​​probleem tegen waar ik het had toegewezen request.user naar een variabele genaamd prior_user, vervolgens in wezen de gebruiker geauthenticeerd, vervolgens gecontroleerd om te zien of request.user != prior_user. Ik verwachtte dat ze niet hetzelfde zouden zijn en dat prior_user moet 'AnonymousUser' bevatten. Tot mijn verbazing waren ze hetzelfde.

Voorbeeldcode:

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!

Ik ontdekte dat prior_user eigenlijk een instantie van django.utils.functional.SimpleLazyObject bevat, dus ik neem aan dat het een soort lui lookup-type is, dat wil zeggen dat de waarde van prior_user niet wordt opgezocht totdat deze daadwerkelijk wordt gebruikt. Kijkend naar de broncode, kan ik dit niet bevestigen.

Iedereen met Django-ervaring kan me vertellen wat er aan de hand is en waarom het nodig is?

Dit maakt me een beetje geschrokken, omdat de gebruikelijke opdrachtafspraak niet werkt zoals ik verwacht en wat anders binnen Django zo werkt? Ook zag ik dit niet beschreven in de docs.

Dus iedereen met super menselijke kennis van Django kan wat duidelijkheid verschaffen?


42
2018-05-08 21:27


oorsprong


antwoorden:


De auth middleware voegt een toe user attribuut aan request dat is een voorbeeld van SimpleLazyObject. SimpleLazyObject, zelf is een subklasse van LazyObject. LazyObject is, zoals beschreven door de daadwerkelijke code:

Een wrapper voor een andere klasse die kan worden gebruikt om instantiatie van de gewikkelde klasse te vertragen

SimpleLazyObject stelt alleen die klasse in (de _wrapped attribuut aan LazyObject) via een doorgegeven methode, in dit geval get_user. Hier is de code voor die methode:

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

Dat is op zich eigenlijk alleen maar een verpakking auth.get_user, dat een soort caching-mechanisme mogelijk maakt. Dus dit is wat uiteindelijk wordt uitgevoerd:

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

Dus, alles wat hier echt gebeurt, is dat request.user is ambigu totdat het ergens voor wordt gebruikt. Dit is belangrijk omdat het zich kan aanpassen aan de actueel authenticatiestatus. Als u toegang krijgt tot een eigenschap die erop staat voor je authenticeert, het geeft een instantie terug AnonymousUser, maar als u zich authenticeert en er vervolgens toegang toe krijgt, wordt er een exemplaar van geretourneerd User.


100
2018-05-08 22:01