如果用户未登录,我希望登录表单(来自django.contrib.auth的AuthenticationForm)显示在我站点的每个页面上。当用户登录时,它们将被重定向到同一页面。如果出现错误,错误将显示在带有表单的同一页面上。
我想你需要一个上下文处理器来为每个模板提供表单。但是,那么你还需要每个视图来处理发布的表单吗?这是否意味着您需要创建一些中间件?我有点失落。
有没有可以接受的方法呢?
答案 0 :(得分:34)
好吧,我最终找到了这样做的方法,虽然我确信有更好的方法。我创建了一个名为LoginFormMiddleware的新中间件类。在process_request方法中,或多或少地按照auth登录视图的方式处理表单:
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”已添加到表单中,因此我可以将其与页面上的其他已发布表单区分开来。此外,表单操作是“。”而不是auth登录视图。
答案 1 :(得分:25)
使用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'
在模板上下文处理器中。这样,您就不必为登录编写任何上下文处理器,因为您使用的是Django内置视图。
答案 2 :(得分:6)
最简单的方法可能是将表单手动放入基本模板中,如下所示:
{% 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的视图来处理正常的表单(使用与上述表单匹配的表单对象)。将视图重定向到request.META['HTTP_REFERER']
,以便将其显示在与提交的页面相同的页面上。
这种方法避免了中间件或需要通过上下文为每个模板提供表单。
更新:此方法存在一些问题;需要多考虑一下。希望它至少能让你朝着正确的方向前进。
答案 3 :(得分:2)
根据asciitaxi的答案,我使用这些中间件类来登录和注销:
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 %}
说明: