回到顶部

Contents

Django form 里 password1 password2 验证先后探索(注册表单)

首先,我们看看能正常验证两次密码一致性的注册表单 :

from __future__ import unicode_literals

import unicodedata

from django import forms
from django.contrib.auth import (
    authenticate, get_user_model, password_validation,
)
from django.forms.widgets import TextInput


class UsernameField(forms.CharField):
    def to_python(self, value):
        return unicodedata.normalize('NFKC', super(UsernameField, self).to_python(value))


class UserRegisterForm(forms.ModelForm):
    """
    学生注册表单
    """
    password1 = forms.CharField(
        label="确认密码",
        widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入确认密码'}),
        strip=False,
        help_text="请输入确认密码")

    password2 = forms.CharField(
        label="确认密码",
        widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入确认密码'}),
        strip=False,
        help_text="请输入确认密码",
    )

    class Meta:
        model = User
        fields = ("username",)
        field_classes = {'username': UsernameField}
        widgets = {
            'username': TextInput(attrs={'class': 'form-control', 'placeholder': '请输入您的姓名'}),
        }

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        print("p2---\n",type(password2), password2)
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("两次密码不一致")
        # self.instance.username = self.cleaned_data.get('username')
        # password_validation.validate_password(self.cleaned_data.get('password2'), self.instance)
        return password2

本段代码链接:https://gitee.com/yinzhuoqun/StudentsManager/blob/master/students/views.py

假设现在把上面的 UserRegisterForm 表单的 clean_password2 改成 clean_password1 后,form.is_valid() 验证的时候会出现什么现象呢?

答案是:会出现两次密码的一致性验证失效,这到底是为啥?在代码里的表现就是,在 clean_password1 里面 get password2 的值是空的,跳过了密码一致性验证的逻辑。

System check identified no issues (0 silenced).
March 06, 2020 - 18:47:27
Django version 2.2.7, using settings 'StudentsManager.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
p2---
 {'username': '张4全', 'password1': 'django123456'}
p2 <class 'NoneType'> None
[06/Mar/2020 18:47:36] "POST /register HTTP/1.1" 200 2192

查询 django 文档 有这么几句话:

  • Field子类的clean() 方法。它负责以正确的顺序运行to_pythonvalidate 和 run_validators 并传播它们的错误。如果任何时刻、任何方法引发ValidationError,验证将停止并引发这个错误。这个方法返回验证后的数据,这个数据在后面将插入到表单的 cleaned_data 字典中。

  • 表单子类中的clean_<fieldname>() 方法 —— <fieldname> 通过表单中的字段名称替换。这个方法完成于特定属性相关的验证,这个验证与字段的类型无关。这个方法没有任何传入的参数。你需要查找self.cleaned_data 中该字段的值,记住此时它已经是一个Python 对象而不是表单中提交的原始字符串(它位于cleaned_data 中是因为字段的clean() 方法已经验证过一次数据)。

    例如,如果你想验证名为serialnumber 的CharField 的内容是否唯一, clean_serialnumber() 将是实现这个功能的理想之处。你需要的不是一个特别的字段(它只是一个CharField),而是一个特定于表单字段特定验证,并规整化数据。

    这个方法返回从cleaned_data 中获取的值,无论它是否修改过。

  • 表单子类的clean() 方法。这个方法可以实现需要同时访问表单多个字段的验证。这里你可以验证如果提供字段A,那么字段B 必须包含一个合法的邮件地址以及类似的功能。 这个方法可以返回一个完全不同的字典,该字典将用作cleaned_data

我的理解是,还没被 clean() 验证的字段不会放入到 cleaned_data 中, 当要验证码 该字段时才放入到 cleaned_data 中。这样就会导致没验证 password2 时,在验证 clean_password1 中 password2 的值为 None.

Django 表单验证的源码剖析:

^_^
请喝咖啡 ×

前一篇: Django 用户权限、用户角色使用指南(转)
下一篇: Django CKEditor 给 a tag(标签)添加 target 默认值
captcha