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!

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

Любой, кто имеет опыт работы с Django, может рассказать мне, что происходит и зачем это нужно?

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

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

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,

Другие вопросы по тегам