Django LoginFormMiddleware打破了基于类的视图

2024-10-02 14:26:35 发布

您现在位置:Python中文网/ 问答频道 /正文

根据一些other SO answers,我使用中间件在我的项目的每个页面上显示一个登录表单,这样用户就可以就地登录了。我知道有些人不赞成这一点,但它确实有助于更好的用户体验。理想情况下是异步的,但我还没有做到。在

不管怎样,中间件.py公司名称:

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'

以及视图.py公司名称:

^{pr2}$

您会注意到,我已经注释了旧的index view函数,并将其替换为基于类的视图。通常我不会子类化,而是将模板名传入网址.py但这不是重点。我的问题似乎是中间件坏了。在索引页面上填写UN/Pass,然后提交,中间件捕获表单并让我登录,但是django继续返回一个空白的http响应。没有错误,但也没有呈现索引页。我只是不知道休息在哪里。在


Tags: 中间件thedjangoinfrompyimportform
2条回答

在基于类的视图中,默认的dispatch方法尝试委托给与HTTP方法相对应的方法。

^{}只实现一个get()方法,因此它只适用于GET请求。当您使用POST请求登录时,dispatch方法查找TemplateView.post()方法。因为这不存在,它返回一个HTTP错误405(不允许使用方法)。

在中间件中,我建议您在成功登录后重定向到同一个url。一般来说,这个Post/Redirect/Get模式是一个很好的建议。浏览器将遵循重定向,并使用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请求。

为了最终确定这个问题,阿拉斯代尔的回答是恰到好处的。我使用的最后一个代码是

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('')

这解决了原始问题,并在成功处理(登录、注销)数据时发出重定向,以便用户触发的刷新不会提示重新发送表单。

相关问题 更多 >