request.user返回一个SimpleLazyObject,我如何“唤醒”它?

时间:2012-07-03 16:06:30

标签: python django django-users django-contrib

我有以下方法:

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

从视图中调用:

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

如您所见,_attempt方法期望actor为django.contrib.auth.models.User类型,但该对象似乎是django.utils.functional.SimpleLazyObject类型。为什么会这样?更重要的是,如何将LazyObject(显然是一种User对象的包装器)转换为User对象?

此处提供了有关Request.user的更多信息:https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.user此文档似乎表明request.user应该是User对象......

======后编辑=====

我现在有以下方法:

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

我正在传递用户,但是if条件仍然是真的,演员仍然是LazyObject。为什么会这样?

6 个答案:

答案 0 :(得分:34)

请参阅my answer on a similar question

Django延迟加载request.user,以便它可以是UserAnonymousUser,具体取决于身份验证状态。它只会“唤醒”并在访问属性时返回相应的类。不幸的是,__class__不计算,因为这是一个原始类属性。在某些情况下,您可能需要知道这实际上是SimpleLazyObject类型,因此将其代理到UserAnonymousUser是错误的。

长短,你根本无法进行这种比较。但是,你真正试图在这里实现的目标是什么?如果您要检查它是User还是AnonymousUser,那么例如request.user.is_authenticated()就可以了。

但作为一般规则,你不应该滥用鸭子打字。参数应始终是特定类型或子类型(UserUserSubClass),即使它 也不是。否则,你最终会得到令人困惑和脆弱的代码。

答案 1 :(得分:14)

这应该这样做:

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

我必须写这个,所以我可以将用户添加到会话字典中。 (SimpleLazyObjects不可选!)

答案 2 :(得分:9)

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

然后您使用user代替request.user

这类似于UsAaR33的答案,但是单行程转换对象更好。

答案 3 :(得分:1)

对于想要为您的代码编写失败的“小”单元测试的任何人,您可以生成一个包装的User并将其填入请求中。

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)

请参阅:

答案 4 :(得分:0)

这可能对其他人有帮助,并且更清洁。

如果SimpleLazyObject包含的实例属于提供的类,则返回python方法 isinstance(instance,class)

if isinstance(request.user, User):
    user = request.user

答案 5 :(得分:0)

像这样更改您的代码,应该没有问题:

from copy import deepcopy

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