Python Django LoginFormMiddleware使用基于类的视图
根据一些例子,我正在使用中间件在我的项目的每个页面上显示一个登录表单,这样用户就可以就地登录。我知道有些人对此表示不满,但这确实有助于获得更好的用户体验。理想情况下,它是异步的,但我还没有实现 无论如何,middleware.py:Python Django LoginFormMiddleware使用基于类的视图,python,django,django-class-based-views,Python,Django,Django Class Based Views,根据一些例子,我正在使用中间件在我的项目的每个页面上显示一个登录表单,这样用户就可以就地登录。我知道有些人对此表示不满,但这确实有助于获得更好的用户体验。理想情况下,它是异步的,但我还没有实现 无论如何,middleware.py: from MyProj.forms import MyProjTopLoginForm from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse
from MyProj.forms import MyProjTopLoginForm
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
#Notes: https://stackoverflow.com/questions/2734055/putting-a-django-login-form-on-every-page
class LoginFormMiddleware(object):
def process_request(self, request):
# if the top login form has been posted
if request.method == 'POST' and 'top_login_form-username' in request.POST:
# validate the form
form = MyProjTopLoginForm(prefix="top_login_form", data=request.POST)
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
# if this is the logout page, then redirect to /
# so we don't get logged out just after logging in
if reverse('logout') in request.get_full_path():
return HttpResponseRedirect('/')
#return HttpResponseRedirect('/')
else:
form = MyProjTopLoginForm(request, prefix="top_login_form")
# attach the form to the request so it can be accessed within the templates
request.top_login_form = form
class LogoutFormMiddleware(object):
def process_request(self, request):
if request.method == 'POST' and request.POST.has_key('logout-button') and request.POST['logout-button'] == 'logout':
from django.contrib.auth import logout
logout(request)
request.method = 'GET'
和views.py:
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.db.models import Count
from django.core.urlresolvers import reverse
from django.views.generic import TemplateView
class Index(TemplateView):
template_name = 'KReport2/index.djhtml'
'''
def index(request):
return render(request, 'KReport2/index.djhtml')
'''
def logoutpage(request):
from django.contrib.auth import logout
logout(request)
return redirect(index)
您会注意到,我对旧的索引视图函数进行了注释,并将其替换为基于类的视图。通常我不会子类化,而是在url.py中传递template_name,但这不是重点。我的问题似乎是中间件坏了。在索引页面上填写UN/Pass,然后提交,中间件捕获表单并让我登录,但django继续返回一个空白http响应。没有错误,但也没有呈现的索引页。我只是不知道中断发生在哪里。在基于类的视图中,默认方法尝试委托给与HTTP方法对应的方法 只实现了一个
get()
方法,因此它只适用于get请求。当您使用POST
请求登录时,dispatch方法将查找TemplateView.POST()
方法。因为这不存在,所以它返回HTTP错误405(不允许使用方法)
在您的中间件中,我建议您在成功登录后重定向到相同的url。一般来说,这种模式是很好的建议。浏览器将遵循重定向,并通过GET请求获取IndexView
,这将是成功的
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
# if this is the logout page, then redirect to /
# so we don't get logged out just after logging in
if reverse('logout') in request.get_full_path():
return HttpResponseRedirect('/')
# redirect to the same url after a successful POST request.
return HttpResponseRedirect('')
最后,浏览器可能会显示一个空白页面,但还有更多信息可用于调试。Django dev服务器将显示它返回了405错误代码。使用浏览器的开发者工具栏,它应该向您显示错误代码
405 METHOD NOT ALLOWED
,以及Allow:get,head
标题,该标题告诉您视图不允许post请求。要完成此问题,Alasdair的答案是正确的。我使用的最后一个代码是
from MyProj.forms import MyProjTopLoginForm
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
#Notes: http://stackoverflow.com/questions/2734055/putting-a-django-login-form-on-every-page
class LoginFormMiddleware(object):
def process_request(self, request):
# if the top login form has been posted
if request.method == 'POST' and 'top_login_form-username' in request.POST:
# validate the form
form = MyProjTopLoginForm(prefix="top_login_form", data=request.POST)
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
# if this is the logout page, then redirect to /
# so we don't get logged out just after logging in
if reverse('logout') in request.get_full_path():
return HttpResponseRedirect('/')
# Redirect to the same page after successfully handling the login form data.
return HttpResponseRedirect('')
# We could also do:
# request.method = 'GET'
# instead of a redirect, but if a user refreshes the page, they'll get prompted to re-send post data,
# which is super annoying.
else:
form = MyProjTopLoginForm(request, prefix="top_login_form")
# attach the form to the request so it can be accessed within the templates
request.top_login_form = form
class LogoutFormMiddleware(object):
def process_request(self, request):
if request.method == 'POST' and request.POST.has_key('logout-button') and request.POST['logout-button'] == 'logout':
from django.contrib.auth import logout
logout(request)
# Same as above. Handle the post data, then redirect to a new GET (not POST) request.
return HttpResponseRedirect('')
这解决了原始问题,并在成功处理(登录、注销)数据时发出重定向,这样用户触发的刷新不会提示重新发送表单。!回答得很好,谢谢。尽管我想到LogoutFormMiddleware已经解决了这个问题,只需在注销完成后设置request.method='GET',视图就可以使用GET方法处理,从而解决问题。在我看来,这似乎比向同一个URL发出重定向更好,尽管我不确定它的优点是什么(也许有一点点速度?),理论上不重定向更快,但我不知道用户是否会注意到实践中的任何差异。在中间件中更改
request.method
,对我来说似乎有点骇人。就我个人而言,我会避免这样做。在成功的post请求后重定向通常是一个好习惯。在这种情况下,这是不必要的,因为没有风险,例如支付被处理两次。如果用户在登录后立即刷新页面,重定向将阻止用户获得“是否要重新提交请求”确认消息。我认为这是一个可用性的改进。