68

我有以下方法:

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

从视图中调用:

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

如您所见, _attempt 方法期望 actor 是 type django.contrib.auth.models.User,但对象似乎是 type django.utils.functional.SimpleLazyObject。为什么会这样?更重要的是,如何将LazyObject(显然是用户对象的一种包装器)转换为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条件仍然是 true,actor 仍然是LazyObject. 为什么会这样?

4

7 回答 7

43

请参阅我对类似问题的回答

Django 延迟加载request.user,因此它可以是UserAnonymousUser取决于身份验证状态。它仅在访问属性时“唤醒”并返回适当的类。不幸的是,__class__这不算数,因为这是一个原始的类属性。有时您可能需要知道这实际上是一种SimpleLazyObject类型,因此将其代理到Useror是错误的AnonymousUser

总而言之,您根本无法进行这种比较。但是,你真正想在这里实现什么?例如,如果您试图检查它是否是 aUserAnonymousUser,那么就是request.user.is_authenticated()这样。

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

于 2012-07-03T17:00:00.663 回答
19

这应该这样做:

# 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 不可腌制!)

于 2012-11-09T08:14:44.427 回答
11
user= request.user._wrapped if hasattr(request.user,'_wrapped') else request.user

然后你使用user而不是request.user.

这类似于 UsAaR33 的答案,但单行更适合转换对象。

于 2013-04-30T16:29:14.457 回答
3

对于任何想为您的代码编写失败的“小型”单元测试的人,您可以生成一个包装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)

看:

于 2016-12-15T19:22:47.563 回答
1

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

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

if isinstance(request.user, User):
    user = request.user
于 2019-10-24T09:38:28.610 回答
0

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

from copy import deepcopy

def _attempt(actor):
    actor = deepcopy(actor)
    if actor.__class__ != User:
        raise TypeError
于 2020-02-22T10:21:38.843 回答
0

这是auth_userDjango 中表的模式 -

id
password
last_login
is_superuser
username
last_name
email
is_staff
is_active
date_joined
first_name

现在,如果您想id这样写-

req.user.id

如果你想username这样写 -

req.user.username
于 2021-11-13T18:14:31.600 回答