request.user returns a SimpleLazyObject, how do I “wake” it?

后端 未结 6 1881
萌比男神i
萌比男神i 2020-12-05 03:57

I have the following method:

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

Which is called from a view:

相关标签:
6条回答
  • 2020-12-05 04:21

    For anyone wanting to write a failing "small" unittest for your code, you can generate a wrapped User and stuff it inside a request.

    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)
    

    See:

    • https://github.com/django/django/blob/master/tests/utils_tests/test_lazyobject.py for current tests on the Lazy Objects.

    • https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.RequestFactory for latest info on the RequestFactory.

    0 讨论(0)
  • 2020-12-05 04:39

    change your code like this and there should be no problem:

    from copy import deepcopy
    
    def _attempt(actor):
        actor = deepcopy(actor)
        if actor.__class__ != User:
            raise TypeError
    
    0 讨论(0)
  • 2020-12-05 04:40
    user= request.user._wrapped if hasattr(request.user,'_wrapped') else request.user
    

    Then you use user instead of request.user.

    This is similar to UsAaR33's answer, but a one-liner is nicer for converting the object.

    0 讨论(0)
  • 2020-12-05 04:44

    This should do it:

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

    I had to write this so I could add a user to the session dictionary. (SimpleLazyObjects are not picklable!)

    0 讨论(0)
  • 2020-12-05 04:45

    This might be helpful to others and a bit cleaner.

    The python method isinstance(instance, class) returns if the SimpleLazyObject's contained instance is of the provided class.

    if isinstance(request.user, User):
        user = request.user
    
    0 讨论(0)
  • See my answer on a similar question.

    Django lazy loads request.user so that it can be either User or AnonymousUser depending on the authentication state. It only "wakes up" and returns the appropriate class when an attribute is accessed on it. Unfortunately, __class__ doesn't count because that's a primitive class attribute. There's occasions where you might need to know that this is actually a SimpleLazyObject type, and therefore it would be wrong to proxy it on to User or AnonymousUser.

    Long and short, you simply can't do this comparison as you have it. But, what are you really trying to achieve here? If you're trying to check if it's a User or AnonymousUser, there's request.user.is_authenticated() for that, for example.

    As a general rule though, you shouldn't abuse duck typing. A parameter should always be a particularly type or subtype (User or UserSubClass), even though it doesn't have to be. Otherwise, you end up with confusing and brittle code.

    0 讨论(0)
提交回复
热议问题