Подтвердить что ты не робот

Django: Цель django.utils.functional.SimpleLazyObject?

У меня возникла проблема, когда я назначил request.user переменной с именем prior_user, затем по существу аутентифицировал пользователя, а затем проверил, есть ли request.user != prior_user. Я ожидал, что они не будут одинаковыми и что prior_user должен содержать `AnonymousUser. К моему удивлению, они были такими же.

Пример кода:

prior_user = request.user   # request object, obtained froma  view
authenticate_user(request)   # some function that authenticates
print prior_user.username != request.user.username   # returns False i.e.they are the same!

Затем я обнаружил, что before_user фактически содержит экземпляр django.utils.functional.SimpleLazyObject, поэтому я предполагаю, что это своего рода ленивый тип типа поиска, т.е. значение before_user не просматривается до фактического использования. Если посмотреть на исходный код, я не могу это подтвердить.

Кто-нибудь с опытом django может рассказать мне, что происходит и зачем он нужен?

Это оставляет меня немного потрясенным, потому что обычное присваивание не работает так, как я ожидаю, и что еще в Django действует так? Я также не видел этого в docs.

Итак, любой, кто обладает сверхчеловеческими знаниями о джанго, может дать некоторую ясность?

4b9b3361

Ответ 1

Среднее ПО auth добавляет атрибут user к request, который является экземпляром SimpleLazyObject. SimpleLazyObject, сам по себе является подклассом LazyObject. LazyObject, как описано в фактическом коде:

Обертка для другого класса, которая может использоваться для задержки создания экземпляра завернутого класса

SimpleLazyObject просто устанавливает этот класс (атрибут _wrapped на LazyObject) через переданный метод, в данном случае get_user. Здесь код для этого метода:

def get_user(request):
    if not hasattr(request, '_cached_user'):
        request._cached_user = auth.get_user(request)
    return request._cached_user

Это само по себе является всего лишь оберткой вокруг auth.get_user, что позволяет использовать механизм кэширования. Итак, вот что на самом деле в конечном итоге запускается:

def get_user(request):
    from django.contrib.auth.models import AnonymousUser
    try:
        user_id = request.session[SESSION_KEY]
        backend_path = request.session[BACKEND_SESSION_KEY]
        backend = load_backend(backend_path)
        user = backend.get_user(user_id) or AnonymousUser()
    except KeyError:
        user = AnonymousUser()
    return user

Итак, все, что действительно происходит здесь, состоит в том, что request.user неоднозначно, пока оно фактически не используется для чего-то. Это важно, так как позволяет ему адаптироваться в зависимости от текущего состояния аутентификации. Если вы получаете доступ к свойству на нем перед аутентификацией, он возвращает экземпляр AnonymousUser, но если вы аутентифицируете и затем обращаетесь к нему, он возвращает экземпляр user.