Django 1.11 middleware, как правильно перенаправить - PullRequest
0 голосов
/ 31 января 2020

У меня проблемы с промежуточным программным обеспечением, с которым я не могу разобраться. Предполагается, что проект, над которым я работаю, перенаправляет все запросы на посещение любой части сайта на страницу add_company, если пользователь не настроил свою компанию. Для этого я пишу пользовательское промежуточное ПО. Однако следующий код не работает:

class ProjectTrackingMiddleWare(MiddlewareMixin):
    ''' 
        Note that this Middleware should come after all other middlewares 
        in order to 
    '''
    def __init__(self, get_response=None):
        ''' One-time configuration called when the web-server starts '''
        self.get_response = get_response

    def __call__(self, request):
        ''' To be executed on every request.  '''

        the_request = self.process_request(request)
        response = self.get_response(request)  

        return response

    def process_request(self, request):

        the_user = request.user
        print ('the_user: ', the_user)

        ## CASE 1: User is not authenticated -->  Redirect to login page
        if the_user.
            return HttpResponseRedirect(reverse('accounts:login'))      #  <-- This part works

         the_company = the_user.userprofile.employer    
        if the_user and not the_company:
            print ('the company: ', the_company)
            return HttpResponseRedirect(reverse('project_profile:add_company'))   #<-- Does NOT redirect correctly

        if the_user.projects.all().count() > 1:
            request.project = the_user.projects.all().order_by('-date_modified')[0]

        return request

Промежуточное программное обеспечение не перенаправляет на страницу add_company. Вместо этого, если вошедший в систему пользователь, который не настроил проект, попытается посетить страницу, Django позволяет мне посетить страницу:

Когда я пытаюсь посетить домашнюю страницу, перенаправление не происходит. Но вот ошибка, если бы я посетил страницу /development/ на сайте:

Тип исключения: TypeError at / development /

Значение исключения: контекст должен быть вписан вместо HttpResponseRedirect.

, когда я смотрю на контекст, это:

Variable    Value
context     <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/project/add/">
kwargs      {'autoescape': True}
request     <WSGIRequest: GET '/development/'>

Похоже, что происходит перенаправление, когда я пытаюсь посетить страницу /development/ как url="/project/add/"> предполагает, что он выполнял захват на HttpResponseRedirect.

Итак, вот мои вопросы: 1) Кажется, что перенаправление в process_request - это нормально, или это не рекомендуется? Если нет, то где я могу проверить эти глобальные переменные и перенаправить пользователя для правильной настройки?

2) Как получить цепочку перенаправления, аналогичную той, что имеет Клиент:

client.get(reverse(‘dashboard’), follow = True)

Редактировать 1: Как предложено в комментарии Иэйна, я должен был передать the_request методу get_response. Однако это не решило проблему. Django теперь жалуется на то, что HttpResponseRedirect не имеет пути атрибута:

У объекта 'HttpResponseRedirect' нет атрибута 'path'

Что делает это странным, если бы я был для перенаправления, основанного на существовании компании на URL-адрес входа, я получаю эту ошибку, но если я перенаправить анонимного пользователя на URL-адрес входа, я не получаю эту ошибку:

## Redirects successfully when the user is anonymous. If the user is logged-in already, it skips it as expected
if the_user.is_anonymous():
    return HttpResponseRedirect(reverse('accounts:login'))
### Throws attribute excpetion: 'HttpResponseRedirect' object has no attribute 'path'
if not the_company:
    return HttpResponseRedirect(reverse('accounts:login'))

Итак, это выглядит как ошибка связана с объектом запроса. Но я не могу понять это на данный момент. Есть идеи?

Ответы [ 2 ]

1 голос
/ 01 февраля 2020

То, как вы написали свое промежуточное программное обеспечение, не совсем имеет смысла. Ваш метод process_request возвращает объект Response, который вы затем передаете get_response. Это неверно - get_response принимает запрос , а не ответ .

Поскольку в некоторых случаях вы хотите замкнуть ответ, вам нужно полностью пропустить вызов get_response, если вы хотите перенаправить. Это означает, что ваши проверки должны произойти до вызова get_response. Примерно так:

def __call__(self, request):
    # Perform your checks here, and redirect if necessary
    the_user = request.user
    ## CASE 1: User is not authenticated -->  Redirect to login page
    if not the_user:
        return HttpResponseRedirect(reverse('accounts:login'))
    the_company = the_user.userprofile.employer    
    if not the_company:
        return HttpResponseRedirect(reverse('project_profile:add_company'))  

    if the_user.projects.all().count() > 1:
        request.project = the_user.projects.all().order_by('-date_modified')[0]

    # Now that you've done your checks, let the rest of the request process run
    response = self.get_response(request)  
    return response

(отбросьте метод process_request, поскольку он больше не используется).

0 голосов
/ 02 февраля 2020

Я наконец исправил это с помощью ловушки process_view.

AUTHENTICATION_EXEMPT_URLS = (
                           reverse('accounts:signup').lstrip('/'),   # reverse part returns '/accounts/login' and lstrip('/') drops the '/': 'accounts/login'
                           reverse('accounts:login').lstrip('/'),
                           reverse('accounts:logout').lstrip('/'),
                        )

COMPANY_EXEMPT_URLS =  (   reverse('project_profile:add_company').lstrip('/'), 
                       reverse('accounts:signup').lstrip('/'),
                       reverse('accounts:login').lstrip('/'),
                       reverse('accounts:logout').lstrip('/'),
                   )


class MyRedirectMiddleware(MiddlewareMixin):

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):    
        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        assert hasattr(request, 'user')       # being logged in is required
        path = request.path_info.lstrip('/')

        if not request.user.is_authenticated():

            if not any(url for url in AUTHENTICATION_EXEMPT_URLS if url==path):    
            # if the url is not in any of the list's urls, redirect to authentication page
                return redirect(settings.LOGIN_URL)

        #  Note that userprofile is created using a signal currently at user_profile/models.py 
        the_company = request.user.userprofile.employer
        if request.user.is_authenticated() and not the_company:
            # user should setup a copmany first:
            if not any( url for url in COMPANY_EXEMPT_URLS if url==path):
                return redirect(reverse('project_profile:add_company'))

Я должен отметить учебник YouTube и поблагодарить всех, кто нашел время, чтобы помочь, вы великолепны .

...