首页 文章

Django LoginFormMiddleware打破了基于类的视图

提问于
浏览
0

根据一些other SO answers,我是异步的,但我还没有到达那里 .

无论如何,middleware.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'

和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)

你会注意到我已经评论了旧的索引视图函数,并将其替换为基于类的视图 . 通常我不会子类化,而是在urls.py中传递template_name,但这不是这里的重点 . 我的问题似乎是中间件坏了 . 填写索引页面上的UN / Pass,然后提交,中间件捕获表单并登录,但随后django继续返回空白的http响应 . 没有错误,也没有渲染的索引页面 . 我不知道休息发生在哪里 .

2 回答

  • 1

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

    TemplateView仅实现 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 Headers ,告诉您视图不允许发布请求 .

  • 0

    为了最终确定这个问题,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('')
    

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

相关问题