web-dev-qa-db-fra.com

request.user renvoie un SimpleLazyObject, comment le "réveiller"?

J'ai la méthode suivante:

def _attempt(actor):
    if actor.__class__ != User:
        raise TypeError

Qui s'appelle d'une vue:

self.object.attempt(self.request.user)

Comme vous pouvez le voir, la méthode _attempt s'attend à ce que l'acteur soit de type Django.contrib.auth.models.User, mais l'objet semble être de type Django.utils.functional.SimpleLazyObject. Pourquoi cela est-il ainsi? Et plus important encore, comment puis-je convertir le LazyObject (qui est apparemment une sorte de wrapper pour un objet User) en un objet User?

Plus d'informations sur Request.user est disponible ici: https://docs.djangoproject.com/en/dev/ref/request-response/#Django.http.HttpRequest.user Cette documentation semble indiquer le request.user devrait être un objet User ...

====== Post-édition =====

J'ai maintenant la méthode suivante:

def _attempt(obj, action, actor, msg): 
    actor.is_authenticated() 
    if isinstance(actor, LazyObject): 
        print type(actor) 

Je passe un utilisateur, mais la condition if est toujours vraie, l'acteur est toujours un LazyObject. Pourquoi cela est-il ainsi?

54
Himerzi

Voir ma réponse à une question similaire .

Django lazy charge request.user De sorte qu'il puisse être User ou AnonymousUser selon l'état d'authentification. Il ne "se réveille" et retourne la classe appropriée que lorsqu'un attribut y est accédé. Malheureusement, __class__ Ne compte pas car il s'agit d'un attribut de classe primitif. Il peut arriver que vous ayez besoin de savoir qu'il s'agit en fait d'un type SimpleLazyObject, et qu'il serait donc erroné de le proxyer sur User ou AnonymousUser.

Long et court, vous ne pouvez tout simplement pas faire cette comparaison telle que vous l'avez. Mais qu'essayez-vous vraiment de réaliser ici? Si vous essayez de vérifier s'il s'agit d'un User ou AnonymousUser, il y a request.user.is_authenticated() pour cela, par exemple.

En règle générale, vous ne devez pas abuser de la frappe de canard. Un paramètre doit toujours être un type ou un sous-type particulier (User ou UserSubClass), même s'il n'a pas être. Sinon, vous vous retrouvez avec du code confus et cassant.

35
Chris Pratt

Cela devrait le faire:

# handle Django 1.4 pickling bug
if hasattr(user, '_wrapped') and hasattr(user, '_setup'):
    if user._wrapped.__class__ == object:
        user._setup()
    user = user._wrapped

J'ai dû écrire ceci pour pouvoir ajouter un utilisateur au dictionnaire de session. (SimpleLazyObjects ne sont pas picklables!)

16
UsAaR33
user= request.user._wrapped if hasattr(request.user,'_wrapped') else request.user

Ensuite, vous utilisez user au lieu de request.user.

Ceci est similaire à la réponse de UsAaR33, mais une doublure est plus agréable pour convertir l'objet.

9
André Staltz

Pour toute personne souhaitant écrire un "petit" test non conforme pour votre code, vous pouvez générer un User encapsulé et le placer dans une demande.

from Django.contrib.auth import get_user_model
from Django.test import RequestFactory
from Django.utils.functional import SimpleLazyObject

user = get_user_model().objects.create_user(
    username='jacob',
    email='jacob@…',
    password='top_secret',
)

factory = RequestFactory()
request = factory.get('/')
request.user = SimpleLazyObject(lambda: user)

Voir:

1
jamesc