Django 1.11 中间件如何正确重定向
Django 1.11 middleware how to redirect properly
我无法解决中间件的问题。如果用户尚未设置其公司,我正在从事的项目应该将所有访问网站任何部分的请求重定向到 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/
页面,则会出现以下错误:
Exception Type: TypeError at /development/
Exception Value: context must be a dict rather than 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:
正如 Iain 的评论中所建议的,我应该将 the_request 传递给 get_response 方法。但是,这并没有解决问题。 Django 现在抱怨 HttpResponseRedirect 没有属性路径:
'HttpResponseRedirect' object has no attribute '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'))
看来错误与请求对象有关。但是,我现在无法弄清楚。有什么想法吗?
您编写中间件的方式不太合理。您的 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
方法,因为它不再使用)。
我最终解决这个问题的方法是使用 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 tutorial 并感谢所有花时间提供帮助的人,你们太棒了。
我无法解决中间件的问题。如果用户尚未设置其公司,我正在从事的项目应该将所有访问网站任何部分的请求重定向到 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/
页面,则会出现以下错误:
Exception Type: TypeError at /development/
Exception Value: context must be a dict rather than 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: 正如 Iain 的评论中所建议的,我应该将 the_request 传递给 get_response 方法。但是,这并没有解决问题。 Django 现在抱怨 HttpResponseRedirect 没有属性路径:
'HttpResponseRedirect' object has no attribute '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'))
看来错误与请求对象有关。但是,我现在无法弄清楚。有什么想法吗?
您编写中间件的方式不太合理。您的 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
方法,因为它不再使用)。
我最终解决这个问题的方法是使用 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 tutorial 并感谢所有花时间提供帮助的人,你们太棒了。