2012-05-08 10 views
41

me encontré con un problema por el que he asignado request.user a una variable llamada prior_user, a continuación, el usuario autenticado en esencia, después se comprueba para ver si request.user != prior_user. Esperaba que no fueran iguales y que prior_user debería contener `Usuario Anónimo. Para mi sorpresa, eran lo mismo.django: ¿Propósito de django.utils.functional.SimpleLazyObject?

Código de ejemplo:

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! 

entonces descubrí prior_user en realidad contiene una instancia de django.utils.functional.SimpleLazyObject así que supongo que es una especie de cosa de tipo de búsqueda perezosa es decir, valor de prior_user no se busca hasta que realmente se usa. Al mirar el código fuente, no puedo confirmarlo.

¿Alguien con experiencia django puede decirme qué está pasando y por qué es necesario?

Esto me deja un poco de control, debido a que la instrucción de asignación habitual no funciona de la manera que esperan y lo demás dentro de Django actúa así? Tampoco vi esto descrito en el docs.

Entonces, ¿alguien con un conocimiento sobrehumano de django puede proporcionar algo de claridad?

Respuesta

97

El middleware auth agrega un atributo user al request que es una instancia de SimpleLazyObject. SimpleLazyObject, en sí mismo es una subclase de LazyObject. LazyObject es decir, como se describe por el código real:

Una envoltura para otra clase que se puede usar para retrasar la instanciación de la clase envuelto

SimpleLazyObject limita a establecer que clase (el atributo _wrapped en LazyObject) a través de un método aprobado, en este caso, get_user. Aquí está el código para ese método:

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

Eso en sí mismo es en realidad sólo una envoltura alrededor de auth.get_user, que permite una especie de mecanismo de almacenamiento en caché. Así que aquí es lo que en realidad es finalmente ejecutado:

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 

Por lo tanto, todo lo que realmente está pasando aquí es que request.user es ambigua hasta que realmente se utiliza para algo. Esto es importante, ya que le permite adaptarse según el estado de autenticación actual . Si tiene acceso a una propiedad en él antes de se autentica, devuelve una instancia AnonymousUser, pero si se autentifica y luego acceder a ella, devuelve una instancia de User.

+3

¡Gracias, eso fue muy útil para un principiante de django como yo! – donogood

+4

+1 para la gran explicación! – Anoyz