django: objective 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 iethey are the same! 

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

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

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

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

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

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

SimpleLazyObject просто устанавливает этот class (атрибут _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 .

Давайте будем гением компьютера.