Django之forms组件

Django之forms组件

校验字段功能

# reg.html

<form action="" method="post">
    {% csrf_token %}
    <p>用户名<input type="text" name="username"></p>
    <p>密码<input type="text" name="password"></p>
    <p>确认密码<input type="text" name="pwd"></p>
    <p>邮箱<input type="email" name="email"></p>
    <p>手机号<input type="text" name="tel"></p>
    <input type="submit">
</form>
# views.reg
from django import forms
class User(forms.Form):
    name = forms.CharField(min_length=4)
    password = forms.CharField(min_length=4)
    pwd = forms.CharField(min_length=4,)
    email = forms.EmailField()
    tel = forms.CharField()




def reg(request):
    if request.method == ‘POST‘:
        print(request.POST)
        form = User(request.POST)  # 传过来的字典键名和forms的字段名要相同 才能实现检验的功能
                        # 已经校验的form 校验的字段信息会保留if form.is_valid(): # 传过来的键会一 一和User表中的字段进行对应,然后根据规则进行校验 字段可以多不可以少 少了字段或者校验不符 都为false
            print(form.cleaned_data)  # cleaned_data都为校验forms字段中成功的键值
        else:
            print(form.cleaned_data)
            print(123)
            # print(form.errors)  # errors是一个字典 键为校验失败的字段名 值为一个列表 列表中存储错误信息
            # print(type(form.errors))
            # print(type(form.errors.get(‘name‘)))
            # print(form.errors.get(‘name‘)[0])

            return render(request, ‘reg.html‘, locals())
    form = User()
    return render(request, ‘reg.html‘, locals())

form.is_valid():   传过来的键会一 一和User表中的字段进行对应,然后根据规则进行校验,字段可以多不可以少,少了字段或者校验不符,值都为false。

forms.cleaned_data  都为校验forms字段中成功的键值。

form.errors 是一个字典,键为校验失败的字段名,值为一个列表,列表中存储字段的错误信息。

渲染标签功能

上面说到,如果想要用forms对字段进行校验,就要求传入的name和自定义的类的字段名相同,但如果我们不想做这种操作怎么办?

forms提供了渲染标签的功能。

渲染方式1

from django import forms
class User(forms.Form):    name = forms.CharField(min_length=4, label=‘用户名‘)    password = forms.CharField(min_length=4, label=‘密码‘)    pwd = forms.CharField(min_length=4, label=‘确认密码‘)    email = forms.EmailField(label=‘邮箱‘)    tel = forms.CharField(label=‘电话‘)
def reg(request):
    if request.method == ‘POST‘:
        print(request.POST)
        form = User(request.POST)  # 传过来的字典键名和forms的字段名要相同 才能实现检验的功能
        # 已经校验的form 校验的字段信息会保留
        print(form.is_valid())

        if form.is_valid(): # 传过来的键 可以多但是不可以少 少了或者错了 都为false
            print(form.cleaned_data)  # cleaned_data都为校验forms字段中成功的键值
        else:
            print(form.cleaned_data)
            print(123)
            # print(form.errors)  # errors是一个字典 键为校验失败的字段名 值为一个列表 列表中存储错误信息
            # print(type(form.errors))
            # print(type(form.errors.get(‘name‘)))
            # print(form.errors.get(‘name‘)[0])


            return render(request, ‘reg.html‘, locals())
    form = User()
    return render(request, ‘reg.html‘, locals())

我们来分析一下上面的代码,第一次请求网页是get请求,实例化出一个form对象,然后传入模板

Django之forms组件

当我们提交数据,就会走POST的代码,这时form对象中已经有了各个字段以及各个字段的值。

因此再次渲染模板时,可以直接通过form.字段名得到字段的值,通过forms.字段名.label可以得到字段的label值,从而自定义输入框的名字。

forms.CharField forms.EmailField 默认会宣称成<input type=‘text‘>标签

<div class="container">
    <div class="row">
        <div class="col-md-6 col-offset-3">
            <h3>forms渲染标签方式一</h3>
            <form action="" method="post" novalidate="novalidate">
            {#    novalidate 使表单不会验证表单的输入 直接提交数据#}
                {% csrf_token %}
                <p>{{form.name.label}}{{ form.name }}</p>
                <p>{{form.password.label}}{{ form.password }}</p>
                <p>{{form.pwd.label}}{{ form.pwd }}</p>
                <p>{{form.email.label}}{{ form.email }}</p>
                <p>{{form.tel.label}}{{ form.tel }}</p>
                <input type="submit">
            </form>
        </div>
    </div>
</div>

渲染方式二

<h3>forms渲染标签方式二</h3>
<form action="" method="post">
{% csrf_token %}
    {% for field in form %}
        <p>
            <label for="">{{ field.label }}</label>
            {{ field }}
        </p>
    {% endfor %}
</form>

第二种直接通过for循环,更加简单。

渲染方式三

<h3>渲染方式3</h3>
<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
</form>

渲染方式三虽然特别简单,但是不推荐使用,因为这种方式把格式给定死了,当你想要做一些修改的时候不能进行操作。

渲染错误信息

<form action="" method="post" novalidate="novalidate">
            {#    novalidate 使表单不会验证表单的输入 直接提交数据#}
                {% csrf_token %}
                <p>{{form.name.label}}{{ form.name }}<span class="pull-right error">{{ form.name.errors.0 }}</span></p>
                <p>{{form.password.label}}{{ form.password }}<span class="pull-right error">{{ form.password.errors.0 }}</span></p>
                <p>{{form.pwd.label}}{{ form.pwd }}<span class="pull-right error">{{ form.pwd.errors.0 }}</span><span class="pull-right error">{{ errors.0}}</span></p>
                <p>{{form.email.label}}{{ form.email }}<span class="pull-right error">{{ form.email.errors.0 }}</span></p>
                <p>{{form.tel.label}}{{ form.tel }}<span class="pull-right error">{{ form.tel.errors.0 }}</span></p>
                <input type="submit">
            </form>

视图函数仍为上面的函数,第一次请求渲染出页面,第二次做字段校验时,错误的字段会放入forms.errors中,各个字段的错误信息可通过form.字段名.errors.0取出。

如果没有错误,模板语法不会报错,只是什么都不显示;如果有错误,就将错误显示在输入框后。

显示出来的错误信息是Django内部自己定义好的,如果想要自己定义错误信息,可在User表的每一个字段增加error_message属性

 error_messages={‘required‘: ‘该字段不能为空‘, ‘invalid‘:‘输入格式错误‘} 第一个是输入为空时显示的错误信息,第二个是校验不合法时提示的错误信息。

注:forms默认每一个字段不能为空。

forms组件的一些其他参数配置

我们上面定义User类的时候用的是CharField和EmailField,渲染出来的分别是<input type=‘text‘>和<input type=‘email‘>,如果想要改变渲染的类型,或者想给渲染的标签增加一些属性该怎么做呢?

from django import forms
from django.forms import widgets
class User(forms.Form):
    name = forms.CharField(min_length=4, label=‘用户名‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
    password = forms.CharField(min_length=4, label=‘密码‘, widget=widgets.PasswordInput(attrs={‘class‘:‘form-control‘}), error_messages={‘required‘: ‘该字段不能为空‘})
    pwd = forms.CharField(min_length=4, label=‘确认密码‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(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‘}))

通过widget参数可以指定渲染出来的标签类型,同时给标签增加属性。

局部钩子和全局钩子

前面实现的校验功能都是一些非常简单的功能,比如最小长度,邮箱格式。

我们想要实现的目标是可以自定义一些更加复杂的规则,实现一些更加复杂的校验。

from django.shortcuts import render,HttpResponse

# Create your views here.
from django import forms
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError


class User(forms.Form):
    name = forms.CharField(min_length=4, label=‘用户名‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(attrs={‘class‘:‘form-control‘}))
    password = forms.CharField(min_length=4, label=‘密码‘, widget=widgets.PasswordInput(attrs={‘class‘:‘form-control‘}), error_messages={‘required‘: ‘该字段不能为空‘})
    pwd = forms.CharField(min_length=4, label=‘确认密码‘, error_messages={‘required‘: ‘该字段不能为空‘}, widget=widgets.TextInput(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_tel(self):
        val = self.cleaned_data.get(‘tel‘)
        if len(val) == 11:
            return val  # 通过正常返回值
        else:
            raise ValidationError(‘手机号码格式错误‘)  #不通过抛出异常

    def clean_password(self):
        val = self.cleaned_data.get(‘password‘)
        if len(val) >=4 :
            return val
        else:
            raise ValidationError(‘手机号码不能小于四位‘)

    def clean(self):
        password = self.cleaned_data.get(‘password‘)
        pwd = self.cleaned_data.get(‘pwd‘)
        if password: # password没有通过第一次校验 只抛出第一次校验的错误
            if password == pwd:
                return self.cleaned_data
            else:
                raise ValidationError(‘两次密码不一致‘)
        else:
            return self.cleaned_data

def reg(request):
    if request.method == ‘POST‘:
        print(request.POST)
        form = User(request.POST)  # 传过来的字典键名和forms的字段名要相同 才能实现检验的功能
        # 已经校验的form 校验的字段信息会保留
        print(form.is_valid())

        if form.is_valid(): # 传过来的键 可以多但是不可以少 少了或者错了 都为false
            print(form.cleaned_data)  # cleaned_data都为校验forms字段中成功的键值
        else:
            print(form.cleaned_data)
            print(123)
            # print(form.errors)  # errors是一个字典 键为校验失败的字段名 值为一个列表 列表中存储错误信息
            # print(type(form.errors))
            # print(type(form.errors.get(‘name‘)))
            # print(form.errors.get(‘name‘)[0])

            errors = form.errors.get(‘__all__‘) # 全局钩子错误

            return render(request, ‘reg.html‘, locals())
    form = User()
    return render(request, ‘reg.html‘, locals())

通过在类中定义 clean_字段名 的方法,可以实现对字段的自定义校验,成为局部钩子。

通过定义clean方法,可以对多个字段之间进行相互校验,clean方法的校验在局部钩子之后,成为全局钩子。

方法中的返回值和抛出的异常可以参考源码。

局部钩子的字段校验错误,错误信息会放在forms.errors中,键值为字段名,键值为错误信息。

全局钩子的字段校验错误,错误信息也放在forms.error中,键值为‘__all__‘,键值为错误信息。

相关推荐