User 返回一个 SimpleLazyObject,我如何“唤醒”它?

我有以下方法:

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

从一个角度来说:

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

正如您所看到的,_ try 方法期望 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条件仍然为真,Actor 仍然是 LazyObject。为什么会这样?

36280 次浏览

参见 我对类似问题的回答

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

无论长短,你都不能像现在这样进行比较。但是,你 真的试图在这里实现什么呢?例如,如果您想检查它是 User还是 AnonymousUser,那么可以使用 request.user.is_authenticated()

但是,作为一般规则,您不应该滥用 Duck 类型。参数应该始终是特定的类型或子类型(UserUserSubClass) ,即使它不是 。否则,您最终会得到混乱和脆弱的代码。

这个应该可以:

# 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 不可以 picklable!)

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

然后使用 user而不是 request.user

这与 UsAaR33的答案类似,但是一行程序更适合转换对象。

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

参见:

这可能对其他人有帮助,而且更干净一些。

如果 SimpleLazyObject 包含的实例属于提供的类,python 方法 Isinstance (实例,类)将返回。

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

像这样改变你的代码应该不会有问题:

from copy import deepcopy


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

这是 Django-中 auth_user表的模式

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