这是此问题的后续内容: Official advice for printing all Django form errors in a template not working...or not understood
我在我的Django应用中设置了这两个用户:admin/admin
和b/b
(用户/通行证)。这是登录表单:
{% load i18n %} {# For the "trans" tag #}
<!DOCTYPE html>
<html lang="en">
<HTML><HEAD>
<TITLE>Login</TITLE>
</HEAD>
<BODY>
<H1>Login</H1>
<form method="post" id="loginForm" action="{% url 'login' %}">
{% csrf_token %}
---{{ form.as_p }}===
<label><input name="remember" type="checkbox">{% trans "Remember me" %}</label>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{% url 'main_page' %}" />
</form>
</BODY></HTML>
我可以使用任一帐户登录,没问题。 form.as_p
:
现在,我想强制使用用户名和密码的最小/最大长度。我在models.py
:
USERNAME_MIN_LEN = 5
"""
The database allows one-character usernames. We're going to forbid
anything less than five characters.
"""
USERNAME_MAX_LEN = User._meta.get_field('username').max_length
"""
The maximum allowable username length, as determined by the database
column. Equal to
`User._meta.get_field('username').max_length`
"""
PASSWORD_MIN_LEN = 5
"""
The password is stored in the database, not as plain text, but as it's
generated hash. Length is therefore not enforced by the database at all.
We're going to minimally protect users against themselves and impose an
five character minimum. (For real, I'd make this eight. When testing, I
make the password equal to the username, so it's temporarily shorter.)
"""
PASSWORD_MAX_LEN = 4096
"""
Imposing a maximum password length is not recommended:
- https://stackoverflow.com/questions/98768/should-i-impose-a-maximum-length-on-passwords
However, Django prevents an attack vector by forbidding excessively-long
passwords (See "Issue: denial-of-service via large passwords"):
- https://www.djangoproject.com/weblog/2013/sep/15/security/
"""
在django.contrib.auth.forms import AuthenticationForm
的子类中使用它们:
def get_min_max_incl_err_msg(min_int, max_int):
"""A basic error message for inclusive string length."""
"Must be between " + str(min_int) + " and " + str(max_int) + " characters, inclusive."
username_min_max_len_err_msg = get_min_max_incl_err_msg(USERNAME_MIN_LEN, USERNAME_MAX_LEN)
pwd_min_max_len_err_msg = get_min_max_incl_err_msg(PASSWORD_MIN_LEN, PASSWORD_MAX_LEN)
class AuthenticationFormEnforceLength(AuthenticationForm):
"""
An `AuthenticationForm` that enforces min/max lengths.
- https://docs.djangoproject.com/en/1.7/_modules/django/contrib/auth/forms/#AuthenticationForm
Pass this into the login form via the `authentication_form` parameter.
- https://docs.djangoproject.com/en/1.7/topics/auth/default/#django.contrib.auth.views.login
Which is done in `registration/urls.py`.
"""
username = forms.CharField(min_length=USERNAME_MIN_LEN,
max_length=USERNAME_MAX_LEN,
error_messages={
'min_length': username_min_max_len_err_msg,
'max_length': username_min_max_len_err_msg })
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput,
min_length=PASSWORD_MIN_LEN,
max_length=PASSWORD_MAX_LEN,
error_messages={
'min_length': pwd_min_max_len_err_msg,
'max_length': pwd_min_max_len_err_msg })
这是网址:
from auth_lifecycle.registration.view_login import AuthenticationFormEnforceLength
....
url(r"^login/$",
"auth_lifecycle.registration.view_login.login_maybe_remember",
{ "authentication_form": AuthenticationFormEnforceLength },
name="login"),
正如预期的那样,使用admin/admin
登录仍然有效,b/b
现在失败了。但是,它不会打印出任何错误长度的错误。相反,它与
TypeError at /auth/login/ ... unsupported operand type(s) for %=: 'NoneType' and 'dict'
我认为它可能会与&#34;良好的登录但是长度错误&#34;混淆,但同样的错误发生在完全虚假的用户/通行证上,例如x/x
。 &#34; NoneType&#34;暗示没有错误,但显然 是错误的......对吧?
我如何得到这个&#34;糟糕的长度&#34;要打印的邮件,以及导致此TypeError
的原因?
整个view_login.py
,包括登录视图和表单对象(JavaScript使用额外的上下文变量,我已从上述模板中删除):
from auth_lifecycle.models import PASSWORD_MIN_LEN, PASSWORD_MAX_LEN
from auth_lifecycle.models import USERNAME_MIN_LEN, USERNAME_MAX_LEN
from django import forms #NOT django.contrib.auth.forms
#from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.views import login
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext, ugettext_lazy as _
def login_maybe_remember(request, *args, **kwargs):
"""
Login with remember-me functionality and length checking. If the
remember-me checkbox is checked, the session is remembered for
SESSION_COOKIE_AGE seconds. If unchecked, the session expires at
browser close.
- https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-SESSION_COOKIE_AGE
- https://docs.djangoproject.com/en/1.7/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.set_expiry
- https://docs.djangoproject.com/en/1.7/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.get_expire_at_browser_close
"""
if request.method == 'POST' and not request.POST.get('remember', None):
#This is a login attempt and the checkbox is not checked.
request.session.set_expiry(0)
context = {}
context["USERNAME_MIN_LEN"] = USERNAME_MIN_LEN
context["USERNAME_MAX_LEN"] = USERNAME_MAX_LEN
context["PASSWORD_MIN_LEN"] = PASSWORD_MIN_LEN
context["PASSWORD_MAX_LEN"] = PASSWORD_MAX_LEN
kwargs["extra_context"] = context
return login(request, *args, **kwargs)
def get_min_max_incl_err_msg(min_int, max_int):
"""A basic error message for inclusive string length."""
"Must be between " + str(min_int) + " and " + str(max_int) + " characters, inclusive."
username_min_max_len_err_msg = get_min_max_incl_err_msg(USERNAME_MIN_LEN, USERNAME_MAX_LEN)
pwd_min_max_len_err_msg = get_min_max_incl_err_msg(PASSWORD_MIN_LEN, PASSWORD_MAX_LEN)
class AuthenticationFormEnforceLength(AuthenticationForm):
"""
An `AuthenticationForm` that enforces min/max lengths.
- https://docs.djangoproject.com/en/1.7/_modules/django/contrib/auth/forms/#AuthenticationForm
Pass this into the login form via the `authentication_form` parameter.
- https://docs.djangoproject.com/en/1.7/topics/auth/default/#django.contrib.auth.views.login
Which is done in `registration/urls.py`.
"""
username = forms.CharField(min_length=USERNAME_MIN_LEN,
max_length=USERNAME_MAX_LEN,
error_messages={
'min_length': username_min_max_len_err_msg,
'max_length': username_min_max_len_err_msg })
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput,
min_length=PASSWORD_MIN_LEN,
max_length=PASSWORD_MAX_LEN,
error_messages={
'min_length': pwd_min_max_len_err_msg,
'max_length': pwd_min_max_len_err_msg })
# def clean(self):
# raise ValidationError("Yikes")