Django表单正在正确捕获错误的用户/传递长度,但与TypeError崩溃

时间:2015-02-23 19:14:00

标签: python django django-forms

这是此问题的后续内容: Official advice for printing all Django form errors in a template not working...or not understood

我在我的Django应用中设置了这两个用户:admin/adminb/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

正确打印了无效的用户/通行证组合错误

screenshot

现在,我想强制使用用户名和密码的最小/最大长度。我在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")

0 个答案:

没有答案