Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django LoginFormMiddleware使用基于类的视图_Python_Django_Django Class Based Views - Fatal编程技术网

Python Django LoginFormMiddleware使用基于类的视图

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

根据一些例子,我正在使用中间件在我的项目的每个页面上显示一个登录表单,这样用户就可以就地登录。我知道有些人对此表示不满,但这确实有助于获得更好的用户体验。理想情况下,它是异步的,但我还没有实现

无论如何,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)

您会注意到,我对旧的索引视图函数进行了注释,并将其替换为基于类的视图。通常我不会子类化,而是在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请求后重定向通常是一个好习惯。在这种情况下,这是不必要的,因为没有风险,例如支付被处理两次。如果用户在登录后立即刷新页面,重定向将阻止用户获得“是否要重新提交请求”确认消息。我认为这是一个可用性的改进。