我有以下方法:
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
。为什么会这样?
答案 0 :(得分:34)
请参阅my answer on a similar question。
Django延迟加载request.user
,以便它可以是User
或AnonymousUser
,具体取决于身份验证状态。它只会“唤醒”并在访问属性时返回相应的类。不幸的是,__class__
不计算,因为这是一个原始类属性。在某些情况下,您可能需要知道这实际上是SimpleLazyObject
类型,因此将其代理到User
或AnonymousUser
是错误的。
长短,你根本无法进行这种比较。但是,你真正试图在这里实现的目标是什么?如果您要检查它是User
还是AnonymousUser
,那么例如request.user.is_authenticated()
就可以了。
但作为一般规则,你不应该滥用鸭子打字。参数应始终是特定类型或子类型(User
或UserSubClass
),即使它 也不是。否则,你最终会得到令人困惑和脆弱的代码。
答案 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