clean 函数导致 .is_valid() 方法在表单 django 1.9.8 中使用时为 return false

clean function causing .is_valid() method to return false when used in form django 1.9.8

在我正在处理的 django 项目中,我编写了一个函数来验证来自登录表单的数据。现在,每当我 运行 登录表单实例上的 is_valid() 方法时,它每次都会 returns false。我一整天都在试图找出导致这个问题的原因。

forms.py:

 from django import forms
 from django.contrib.auth import authenticate, password_validation
 from django.contrib.auth.forms import AuthenticationForm
 from django.contrib.auth.models import User, Group
 from .functions import *
 from .models import *

 class login_form(forms.Form):
     username = forms.CharField(max_length=64, label='Username', widget=forms.TextInput(attrs={'placeholder': 'username...', 'class':'login-field'}))
     password = forms.CharField(max_length=24, label='Password', widget=forms.PasswordInput(attrs={'placeholder': 'password...', 'class':'login-field'}))

     def clean(self, *args, **kwargs):
         username = self.cleaned_data.get('username', None)
         password = self.cleaned_data.get('password', None)
         user_obj = None
         self._errors['username'] = None  #clears default username error
         self._errors['password'] = None  #clears default password error

         if username is not None:
             try:
                 user_obj = User.objects.get(username=username) 

                 if password_validation.validate_password(password, user_obj) is None:
                     self._errors['password'] = 'Password is incorrect. Please try again.'

             except User.DoesNotExist:
                 self._errors['username'] = 'User does not exist. Please use valid credentials.'

         else:
             self._errors['username'] = 'Please type a valid username.'


         return super(login_form, self).clean(*args, **kwargs)

views.py:

from django.shortcuts import render, redirect
from django.http import HttpRequest, JsonResponse, HttpResponse
from django.template import RequestContext
from django.conf.urls import patterns
from django.contrib import admin
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User, Group
from datetime import datetime
from .models import *
from .forms import *
from .functions import *
from os import *
import shutil
import json


 def home(request):
     if request.method == 'POST':
        form = login_form(request.POST)

        if form.is_valid():
            username = form.data.get('username')
            password = form.data.get('password')
            authenticate_usr_obj = authenticate(username=username, password=password)
            if authenticate_usr_obj is not None:
                login(request, authenticate_usr_obj)
                return redirect(dashboard)

     else:
         form = login_form()


     try:
        logout_successful = request.session.get('logout_complete', False)
        request.session['logout_complete'] = False

     except:
         logout_successsful = False

     context = {
        'body_class': 'login',
        'login': form,
        'logout_successful': logout_successful
     }

     return render(request, 'development/index.html', context)

通过阅读 Forms API 文档,我可以看到在您的示例中,您在尝试将数据排成行之前没有清理数据:

username = self.cleaned_data.get('username', None)
password = self.cleaned_data.get('password', None)

尝试首先使用 clean() 来验证数据,如下所示:

cleaned_data = super(login_form, self).clean()

那你可以尝试这样获取:

username = cleaned_data.get('username', None)
password = cleaned_data.get('password', None)

您可以找到更多 here

版本 2:

好的,首先我在 Django 文档中发现了关于 django.contrib.auth.password_validation.validate_password():

Integrating validation

validate_password(password, user=None, password_validators=None)

Validates a password. If all validators find the password valid, returns None. If one or more validators reject the password, raises a ValidationError with all the error messages from the validators.

The user object is optional: if it’s not provided, some validators may not be able to perform any validation and will accept any password.

所以行:

if password_validation.validate_password(password, user_obj) is None:

应该是:

if password_validation.validate_password(password, user_obj) is not None:

第二个:

Form.errors

>>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}`

In this dictionary, the keys are the field names, and the values are lists of Unicode strings representing the error messages. The error messages are stored in lists because a field can have multiple error messages.

因此,基于此,我会更改您定义自定义消息的行,使其看起来更像这样:

self.errors['password'] = [u'Password is incorrect. Please try again.']

最后一件事要记住,clean 方法必须 return cleaned_data.

forms.py 代码的最终版本可能如下所示:

def clean(self):
    super(login_form,self).clean()
    username = self.cleaned_data.get('username', None)
    password = self.cleaned_data.get('password', None)

    if username is not None:
        try:
            user_obj = User.objects.get(username=username) 
            if password_validation.validate_password(password, user_obj) is not None:
                self.errors['password'] = [u'Password is incorrect. Please try again.']
        except User.DoesNotExist:
            self.errors['username'] = [u'User does not exist. Please use valid credentials.']
    else:
        self.errors['username'] = [u'Please type a valid username.']
    return self.cleaned_data

希望这次能有所帮助。

测试了你上面的代码,我遇到了表单错误 self._errors

`Nonetype` object is not iterable

这是我的建议

forms.py

from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError


class login_form(forms.Form):
    username = forms.CharField(
        max_length=64, label='Username',
        widget=forms.TextInput(
            attrs={'placeholder': 'username...', 'class': 'login-field'}))
    password = forms.CharField(
        max_length=24, label='Password',
        widget=forms.PasswordInput(
            attrs={'placeholder': 'password...', 'class': 'login-field'}))

def clean_username(self):
    data = self.cleaned_data.get('username', None)
    if not data:
        raise ValidationError('Please type a valid username.',
                              code='invalid')
    return data

def clean(self, *args, **kwargs):
    username = self.cleaned_data.get('username')
    password = self.cleaned_data.get('password')
    try:
        user_obj = User.objects.get(username=username)
        if not user_obj.check_password(password):
            raise ValidationError(
                    'Password is incorrect. Please try again',
                    code='incorrect')

    except User.DoesNotExist:
        raise ValidationError(
            'User does not exist. Please use valid credentials.',
            code='invalid')
    return super(login_form, self).clean(*args, **kwargs)

views.py

from django.shortcuts import render
from django.contrib.auth import authenticate, login
from django.contrib.auth import logout

from .forms import *


def home(request):
    logout_successful = True
    if request.method == 'POST':
        form = login_form(request.POST)
        # print form.errors

        if form.is_valid():
            username = form.data.get('username')
            password = form.data.get('password')
            authenticate_usr_obj = authenticate(
                username=username, password=password)
            if authenticate_usr_obj:
                login(request, authenticate_usr_obj)
                # print 'ok'
    else:
        form = login_form()
    logout_successful = request.user.is_authenticated()
    return render(request, 'base.html', {
        'body_class': 'login',
        'login': form,
        'logout_successful': logout_successful
    })


def logout_view(request):
    logout(request)

我还是个初学者,所以请随意发表评论