0

他のいくつかの 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/Pass を入力して送信すると、ミドルウェアがフォームをキャプチャしてログインしますが、django は空白の http 応答を返します。エラーはありませんが、レンダリングされたインデックス ページもありません。休憩がどこで起こっているのかわかりません。

4

2 に答える 2

1

クラス ベースのビューでは、HTTP メソッドに対応するメソッドに委任しようとするデフォルトのディスパッチメソッドが試みられます。

はメソッドTemplateViewのみを実装するget()ため、GET リクエストに対してのみ機能します。リクエストでログインするとPOST、dispatch メソッドは method を探しTemplateView.post()ます。これは存在しないため、HTTP エラー 405 (メソッドは許可されていません) を返します。

ミドルウェアでは、ログインに成功した後に同じ URL にリダイレクトすることをお勧めします。このPost/Redirect/Getパターンは、一般的に良いアドバイスです。ブラウザはリダイレクトに従い、IndexViewGET リクエストで を取得します。これは成功します。

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ヘッダーが表示されます。

于 2013-04-22T21:48:48.523 に答える
0

この質問を締めくくるために、アラスデアの答えは的を射ています。私が使用している最終的なコードは

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

これにより、元の問題が解決されるだけでなく、(ログイン、ログアウト) データの処理が成功したときにリダイレクトが発行され、ユーザーがトリガーした更新でフォームの再送信を求められなくなります。

于 2013-04-25T00:23:43.903 に答える