Django的LoginFormMiddleware打破了基于类的意见(Django LoginFo

2019-08-31 19:45发布

按照一些其他的SO答案 ,我使用的中间件来显示我的项目的每一个页面上的登录表单,这样用户可以就地登录。 我有些看不惯这种感知,但它确实使一个更好的用户体验。 理想情况下它会是异步的,但我还没有到达那里。

总之,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 /通行证填充索引页,然后提交,中间件捕捉形式,并记录我,但随后的Django接着返回空白HTTP响应。 没有错误,也没有渲染的索引页。 我刚刚拿到了不知道从哪里突破正在发生的事情。

Answer 1:

在基于类的观点,默认调度方法尝试委托给一个方法对应于HTTP方法。

TemplateView只实现了get()方法,所以它仅适用于GET请求。 当您使用登录POST请求,调度方法查找TemplateView.post()方法。 因为这不存在,它返回一个HTTP错误405(方法不允许)。

在你的中间件,我建议你重定向到相同的URL登录成功后。 这个帖子/重定向/获取模式是一般的好建议。 该浏览器将跟随重定向,并获取IndexView用GET请求,这将是成功的。

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的开发服务器将表明,它返回405错误代码。 使用开发者工具栏为您的浏览器,它应该表现出你的错误代码的说明405 METHOD NOT ALLOWED ,并Allow:get, head头,它告诉你的观点不允许POST请求。



Answer 2:

要完成这个问题,麦金太尔的答案是当场上。 我用最后的代码是

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

这解决了原来的问题,以及在发行(登录,注销)数据的成功处置重定向,以便用户触发的刷新不提示重发的形式。



文章来源: Django LoginFormMiddleware breaks with class based views