首页 > 解决方案 > Django 自定义登录表单不会针对 is_valid() 进行验证

问题描述

摘要: 我的自定义登录表单无法针对 .is_valid() 进行验证。我已经能够确认电子邮件和密码值正在传递给views.py,因为print(request.POST.get('')返回电子邮件(登录所需)和密码。

我认为我的问题与其他类似问题不同,因为它们似乎都解决了缺少的必填字段。我尝试从 .is_valid 中排除我能想到的每个字段,但表单无法验证。

我单击按钮,没有任何反应(数据移动,这很奇怪,因为表单仍然无法验证 validate 并且我的登录不起作用 - 请参阅底部的日志)。我正在使用 Django 3.7。

帐户/forms.py

    class LoginForm(forms.Form):
        email = forms.EmailField(label='email', max_length='255')
        password = forms.CharField(label='password')
        
        def __init__(self, request, *args, **kwargs):
            self.request = request
            super(LoginForm, self).__init__(*args, **kwargs)

        def form_valid(self, form):
            form.save()
            return super(LoginForm, self).form_valid(form)

accounts/views.py 我无法访问“form.is_valid”if 语句中的任何内容。我在相应的 else 语句处退出(如下所述)。

    def login_page(request):
        if request.method == 'POST':  #create form instance / populate
             form = LoginForm(request.POST)
             context = {
            "email": "email",
            "password": "password",
            "first_name": "first_name",
            "last_name": "last_name",
            "is_active": "is_active",
            "form": form
            } 
            if form.is_valid():  
                username = form.cleaned_data.get("email")
                password = form.cleaned_data.get("password")
                user = authenticate(request, username=username, password=password)
                form.save()
                if user is not None:
                    if user.is_active:
                        login(request, user)
                        print(request.is_authenticated())
                        context['form'] = LoginForm()
                        return redirect('/')
                    else:
                        pass
                else:
                    pass
            else: 
                '''This is where I always end up in the code'''                                      
                print("Error with if form.is_valid():")
                return render(request, "account/login.html", context)
        else:
            return render(request, "account/login.html")

帐户/urls.py

    app_name = 'accounts'

    from .views import login_page

    urlpatterns = [
        path('login/', login_page, name="login")
        ]

登录.html

    {% extends '_base.html' %}
    {% load static %}
    {% load crispy_forms_tags %}

    {% block title %}Login{% endblock title %}

    {% block content %}
    <h1>Login</h1>
    <form method="post" class="form" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form|crispy }}
            <button class="btn btn-success" type="submit">Log In</button>
    </form>

    {% endblock content %}

settings.py 我拥有 django 推荐用于身份验证和后端的所有必需应用程序。

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'django.contrib.sites',

        # Third-party
        'crispy_forms',

        # Local
        'accounts.apps.AccountsConfig'
    ]

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]


    AUTH_USER_MODEL = 'accounts.User'
    LOGIN_REDIRECT_URL = 'carts:cart_update'
    ACCOUNT_FORMS = {'login': 'accounts.forms.LoginForm'}
    AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.ModelBackend',
        'allauth.account.auth_backends.AuthenticationBackend',
    )
    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    ACCOUNT_SESSION_REMEMBER = True
    ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False
    ACCOUNT_USERNAME_REQUIRED = False
    ACCOUNT_AUTHENTICATION_METHOD = 'email'
    ACCOUNT_EMAIL_REQUIRED = True
    ACCOUNT_UNIQUE_EMAIL = True
    ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 4
    ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 300

accounts/model.py - 自定义用户模型 我正在使用的教程使用自定义用户文件,但我不确定这是否是问题的一部分。我怀疑它不相关,但我将其包括在内以防万一。

    DEFAULT_ACTIVATION_DAYS = getattr(settings, 'DEFAULT_ACTIVATION_DAYS', 7)

    class UserManager(BaseUserManager):
        def create_user(self, email, first_name=None, last_name=None,                 
        password=None, is_active=True, is_staff=False, is_admin=False):
        if not email:
                raise ValueError("Users must have an email address")
        if not password:
               raise ValueError("Users must have a password")
        user_obj = self.model(
               email=self.normalize_email(email),
        )
        user_obj.set_password(password) # change user password
        user_obj.staff = is_staff
        user_obj.admin = is_admin
        user_obj.is_active = is_active
        user_obj.save(using=self._db)
        return user_obj

        def create_staffuser(self, email,first_name=None, last_name=None,         
             password=None):
             user = self.create_user(
                    email,
                    first_name=first_name,
                    last_name=last_name,
                    password=password,
                    is_staff=True
            )
            return user

        def create_superuser(self, email, first_name=None,last_name=None, password=None):
    user = self.create_user(
            email,
            first_name=first_name,
            last_name=last_name,
            password=password,
            is_staff=True,
            is_admin=True
    )
    return user


    class User(AbstractBaseUser):
        email = models.EmailField(max_length=255, unique=True)
        first_name = models.CharField(max_length=255, blank=True, null=True)
        last_name = models.CharField(max_length=255, blank=True, null=True)
        is_active = models.BooleanField(default=True, blank=True, null=True) # can login
        staff = models.BooleanField(default=False, blank=True, null=True) # staff user non superuser
        admin = models.BooleanField(default=False, blank=True, null=True) # superuser
        timestamp = models.DateTimeField(auto_now_add=True, blank=True, null=True)

        USERNAME_FIELD = 'email' #username
        # USERNAME_FIELD and password are required by default
        REQUIRED_FIELDS = [] #['full_name'] #python manage.py createsuperuser

        objects = UserManager()

        def __str__(self):
            return self.email

        def get_first_name(self):
            if self.first_name:
                return self.first_name
            return self.first_name

        def get_email(self):
           return self.email

        def has_perm(self, perm, obj=None):
            return True

        def has_module_perms(self, app_label):
            return True

        @property
        def is_staff(self):
            if self.is_admin:
                return True
            return self.staff

        @property
        def is_admin(self):
            return self.admin

这是我的日志: 我已经确认 print(request.POST.get('') 返回电子邮件和密码,所以我不确定我在这里缺少什么。

    web_1  | <tr><th><label for="id_email">email:</label></th><td><input type="text" name="email" class="form-control" placeholder="Email" maxlength="255" required id="id_email"></td></tr>
    web_1  | <tr><th><label for="id_password">password:</label></th><td><input type="password" name="password" class="form-control" placeholder="Password" required id="id_password"></td></tr>
    web_1  | Error with if form.is_valid():
    web_1  | [20/Mar/2021 10:16:21] "POST /accounts/login/ HTTP/1.1" 200 3192

标签: djangoformsvalidationauthentication

解决方案


我解决了。事实证明,即使所有必填字段都存在,表单也没有绑定。我尝试了很多不同的建议,但最终归结为将 form = LoginForm(request.POST) 修改为 form = LoginForm(request.POST, request.POST)。出于某种原因,有两个 request.POST 允许表单通过 is_valid 测试。我不明白为什么,因为我从未在任何教程等中看到此选项。


推荐阅读