django之form表单验证

form组件的校验功能

 views.py

from django.shortcuts import render, HttpResponse

# Create your views here.

from django import forms
from django.forms import widgets

class UserForm(forms.Form):
    name = forms.CharField(min_length=4,label='用户名') # 必须用required
    pwd = forms.CharField(min_length=4,label='密码')
    r_pwd = forms.CharField(min_length=4,label='确认密码')
    email = forms.EmailField(label='邮箱')
    tel = forms.CharField(label='手机')


def reg(request):
    if request.method == 'POST':

        # form = UserForm({'name': 'ed', 'email': '123@qq.com'})  # 加多少个键值都无所谓,只要能匹配全Form里的字段就会返回True
        # print(form.is_valid())  # 返回布尔值
        

        form = UserForm(request.POST)  # form表单的name属性值应该与forms组件字段名称一致

        if form.is_valid():
            print(form.changed_data)  # 存的是通过校验的字典
        else:
            print(form.cleaned_data)  # {正确的键值,"email":"123@11.com"}
            print(form.errors)  # {"name":["insure this value has at least 4 characters]}

            print(type(form.errors))  # ErrorDict
            print(form.errors.get('name'))
            print(type(form.errors.get('name')))  # ErrorList
            print(form.errors.get('name')[0])  # This field is required.
        '''
        if 所有字段校验成功,则form.cleaned_data:{'name': 'edward', 'email': '123@qq.com'}

        '''
        return render(request, 'register.html', locals())

    form = UserForm()   # get请求的form,渲染form组件用
    return render(request, 'register.html', locals())

html

<form action="" method="post">
    {% csrf_token %}
    <p>用户名:<input type="text" name="user"></p>
    <p>密码:<input type="password" name="pwd"></p>
    <p>确认密码:<input type="password" name="r_pwd"></p>
    <p>邮箱:<input type="email" name="email"></p>
    <p>手机号:<input type="text" name="tel"></p>
    <input type="submit" value="提交">
</form>

form组件渲染的三种方式

<h3>form组件渲染方式1</h3>

<form action="" method="post">
    {% csrf_token %}
    <p>{{ form.name.label }}:{{ form.name }} <span>{{ form.name.errors.0 }}</span></p>
    <p>{{ form.pwd.label }}:{{ form.pwd }} <span>{{ form.pwd.errors.0 }}</span></p>
    <p>{{ form.r_pwd.label }}:{{ form.r_pwd }} <span>{{ form.r_pwd.errors.0 }}</span></p>
    <p>{{ form.email.label }}:{{ form.email }} <span>{{ form.email.errors.0 }}</span></p>
    <p>{{ form.tel.label }}:{{ form.tel }} <span>{{ form.tel.errors.0 }}</span></p>
    <input type="submit" value="提交">
</form>


<hr>
<h3>form组件渲染方式2</h3>
<form action="" method="post">
    {% csrf_token %}

    {% for filed in form %}
        <p>
            <label for="">{{ filed.label }}</label>
            {{ filed }}
        </p>

    {% endfor %}


    <input type="submit" value="提交">
</form>

<hr>
<h3>form组件渲染方式3 --- 不建议使用这种方式,因为它只能固定放那么几个标签,缺乏灵活性,以后改动麻烦</h3>

<form action="" method="post">
    {% csrf_token %}

    {{ form.as_p }}

    <input type="submit" value="提交">
</form>

显示错误信息和参数配置

class UserForm(forms.Form):
    name = forms.CharField(min_length=4, label='用户名',
                           error_messages={"required": "该字段不能为空"},
                           widget=widgets.TextInput(attrs={'class': 'form-control'})
                           )  # 必须用要提示错误信息的关键词
    pwd = forms.CharField(min_length=4, label='密码',
                          widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={
                              "required": "该字段不能为空"
                          })
    r_pwd = forms.CharField(min_length=4, label='确认密码',
                            error_messages={"required": "该字段不能为空"},
                            widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                            )
    email = forms.EmailField(label='邮箱',
                             error_messages={"required": "该字段不能为空", 'invalid': "格式错误"},
                             widget=widgets.TextInput(attrs={'class': 'form-control'}),
                             )
    tel = forms.CharField(label='手机',
                          error_messages={"required": "该字段不能为空", },
                          widget=widgets.TextInput(attrs={'class': 'form-control'}),
                          )

局部钩子

 def clean_name(self):
        val = self.cleaned_data.get('name')

        ret = UserInfo.objects.filter(name=val)

        if not ret:
            return val
        else:
            raise ValidationError('该用户已注册!')
            
            
 def clean_tel(self):
    val = self.cleaned_data.get('tel')
    ret = UserInfo.objects.filter(tel=val)

    if len(ret) == 11:
        return val
    else:
        raise ValidationError('手机号格式错误')
            
# 源码
def _clean_fields(self):
    try:
        if isinstance(field, FileField):
            initial = self.get_initial_for_field(field, name)
            value = field.clean(value, initial)
        else:
            value = field.clean(value)
        self.cleaned_data[name] = value
        if hasattr(self, 'clean_%s' % name):
            value = getattr(self, 'clean_%s' % name)()
            self.cleaned_data[name] = value
     except ValidationError as e :
        self.add_error(name, e)

全局钩子

为了解耦,新建一个myforms.py的文件,把有关forms的代码都放在这里面。

# 全局钩子

# 走完所有的校验才走clean
def clean(self):
    # 走完所有的校验才走clean
    pwd = self.cleaned_data.get('pwd')
    r_pwd = self.cleaned_data.get('r_pwd')
    
    # 都满足不低于4个字符这个条件后才验证密码是否一致
    if pwd and r_pwd:
        if pwd == r_pwd:
            return self.cleaned_data
        else:
            raise ValidationError('两次密码不一致')

            else:
                return self.cleaned_data
        
#源码
def clean(self):
    """
    Hook for doing any extra form-wide cleaning after Field.clean() has been
    called on every field. Any ValidationError raised by this method will
    not be associated with a particular field; it will have a special-case
    association with the field named '__all__'.
    """
    return self.cleaned_data

def _clean_form(self):
    try:
        cleaned_data = self.clean()
    except ValidationError as e:
        self.add_error(None, e)
    else:
        if cleaned_data is not None:
            self.cleaned_data = cleaned_data
            
            
# 全局钩子在前端没有显示,要在处理post请求的代码里给错误信息一个变量并传到前端
errors = form.errors.get('__all__')

# 当两次密码不一致时,在前端显示这个错误
<p>
    {{ form.r_pwd.label }}:{{ form.r_pwd }}
    <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span>
    <span class="pull-right error">{{ errors.0 }}</span>
</p>

原文地址:https://www.cnblogs.com/lshedward/p/10351900.html