在每个页面上放置一个djangologin表单

如果用户没有login,我希望login表单(来自django.contrib.auth的AuthenticationForm)出现在我网站的每个页面上。当用户login时,他们将被redirect到同一页面。 如果出现错误,错误将显示在与表单相同的页面上。

我想你需要一个上下文处理器来为每个模板提供表单。 但是,那么你还需要每个视图来处理张贴的表单? 这是否意味着您需要创build一些中间件? 我有点失落

有没有一个可以接受的方法呢?

好的,我终于find了一个这样做的方法,虽然我确信有更好的方法。 我创build了一个名为LoginFormMiddleware的新中间件类。 在process_request方法中,或多或less处理authlogin视图的方式:

class LoginFormMiddleware(object): def process_request(self, request): # if the top login form has been posted if request.method == 'POST' and 'is_top_login_form' in request.POST: # validate the form form = AuthenticationForm(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 '/account/logout/' in request.get_full_path(): return HttpResponseRedirect('/') else: form = AuthenticationForm(request) # attach the form to the request so it can be accessed within the templates request.login_form = form 

现在,如果您安装了请求上下文处理器,则可以通过以下方式访问表单:

 {{ request.login_form }} 

请注意,表单中添加了一个隐藏字段“is_top_login_form”,所以我可以将其与页面上的其他发布表单区分开来。 此外,表单操作是“。” 而不是authlogin视图。

使用django.contrib.auth,你可以像下面这样将表单代码放在基本模板中:

 <form method="post" action="{% url auth_login %}"> {% csrf_token %} <p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="30" /></p> <p><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></p> <input type="submit" value="Log in" /> <input type="hidden" name="next" value="" /> </form> 

所有你需要做的是修改下一个值,而不是:

 <input type="hidden" name="next" value="" /> 

现在将是:

 <input type="hidden" name="next" value="{{ request.get_full_path }}" /> 

要访问请求对象,请确保包含

 'django.core.context_processors.request' 

在你的模板上下文处理器。 这样,您就不必为login编写任何上下文处理器,因为您正在使用Django内置视图。

最简单的方法可能是将表单手动放置在基本模板中,如下所示:

 {% if user.is_authenticated %} <form action="{% url login %}" method="POST">{% csrf_token %} <input id="username-field" name="username" type="text" /> <input id="password-field" name="password" type="password" /> <button type="submit">Login</button> </form> {% else %} {# display something else here... #} {% endif %} 

然后只需编写一个连接到名为“login”的URL的视图来处理窗体,就像您通常使用与上述窗体匹配的窗体对象一样。 让视图redirect到request.META['HTTP_REFERER']以将其显示在与提交的页面相同的页面上。

这种方法避免了中间件或需要通过上下文使每个模板都可用的表单。

更新 :这种方法有一些问题。 需要多思考一下。 希望至less能让你朝着正确的方向前进。

基于asciitaxi的答案,我使用这些中间件类来login和注销:

 class LoginFormMiddleware(object): def process_request(self, request): from django.contrib.auth.forms import AuthenticationForm if request.method == 'POST' and request.POST.has_key('base-account') and request.POST['base-account'] == 'Login': form = AuthenticationForm(data=request.POST, prefix="login") if form.is_valid(): from django.contrib.auth import login login(request, form.get_user()) request.method = 'GET' else: form = AuthenticationForm(request, prefix="login") request.login_form = form class LogoutFormMiddleware(object): def process_request(self, request): if request.method == 'POST' and request.POST.has_key('base-account') and request.POST['base-account'] == 'Logout': from django.contrib.auth import logout logout(request) request.method = 'GET' 

这在我的基础模板中:

 {% if not request.user.is_authenticated %} <form action="" method="post"> {% csrf_token %} <p id="login"> {{ request.login_form.non_field_errors }} {% for field in request.login_form %} {{ field.errors }} {{ field.label_tag}}: {{ field }} {% endfor %} <input type="submit" name="base-account" value="Login" /> </p> </form> {% else %} <form action="" method="post"> {% csrf_token %} <p id="logout">Logged in as <b>{{ request.user.username }}</b>. <input type="submit" name="base-account" value="Logout" /> </p> </form> {% endif %} 

备注:

  • 其他forms的网站需要request.method ='GET'行。 似乎有点但很尴尬,但它工作正常。
  • 由于这是显示在每一页,我不需要注销特殊情况了,因为我根本不需要一个单独的注销页面
  • 我需要一些区别我的login/注销表单之前检查是否有效(因此调用AuthenticationForm类。否则,将有错误,当涉及到更多的表单的页面。因此,我使用提交button的值挑出相关案件