form组件

前戏:编写用户登录功能,并校验数据返回提示信息

自己手写登录校验功能

前端:
<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        <span style="color: red">{{ user_dict.username }}</span>
    </p>
    <p>password:
        <input type="text" name="password">
        <span style="color: red">{{ user_dict.password }}</span>
    </p>
    <input type="submit">
</form>

后端:
def ab_form(request):
    if request.method == 'POST':
        user_dict = {'username': '', 'password': ''}
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason':
            user_dict['username'] = '用户名不能是jason'
        if password == '123':
            user_dict['password'] = '密码不能是123'
    return render(request, 'ab_form.html', locals())
# 缺陷:每一个字段的匹配规则都要自己手写,而且如果字段很多很麻烦。前端form表单写起来也很繁琐。

form组件介绍

1.数据校验
	支持提前设置好各种校验规则,数据传入之后自动校验
2.渲染页面
	支持直接渲染用来获取用户数据的各种标签
3.展示信息:
	支持针对不同的校验,失败之后展示不同的提示信息

利用form组件编写用户登录校验

form类的创建

from django import forms
class MyForm(forms.Form):
    username = forms.CharField(max_length=8, min_length=3) # 用户名最少3个字符 最多8个字符
    age = forms.IntegerField(max_value=150, min_value=0) # 年龄最少0岁 最多150岁
    email = forms.EmailField() # 邮箱必须符合邮箱格式(至少要有@符号)

数据校验功能

1.传递待校验的数据
	form_obj = views.MyForm({'username': 'jason', 'age': 18, 'email': 'aaa'})  # 邮箱格式不正确
2.判断是否所有的数据都符合校验规则
	print(form_obj.is_valid())  # False
3.获取符合校验的数据
	print(form_obj.cleaned_data)  # {'username': 'jason', 'age': 18}
4.获取不符合校验的数据以及错误原因
	print(form_obj.errors)  # {'email': ['Enter a valid email address.']}
    
'''
1.form类中编写的字段校验时默认都是必填的 少传肯定通不过校验 
2.校验如果多传了一些字段,则这些字段不参与校验,全程忽略
3.指定参数 required=False 表示该字段可以不传值(即不用传值也能校验通过)
'''    

渲染标签功能

先用MyForm实例化一个对象
form_obj = MyForm()

1.方式1:(封装程度高,扩展性差,主要用于快速生成页面本地测试)
	{{ form_obj.as_p }}
	{{ form_obj.as_table }}
	{{ form_obj.as_ul }}
2.方式2:(封装程度低 扩展性好 编写困难)
    {{ form_obj.name.lable }}
    {{ form_obj.name }}
3.方式3:(推荐使用)
	{% for form in form_obj %}
    	<p>
			{{ form.label }}
			{{ form }}
        </p>
    {% endfor %}

'''
类中以外的所有标签都不会自动渲染,需要自己编写
'''

展示提示信息

'''
form类中填写的校验性参数 前端浏览器会识别并自动添加相应的校验操作
但是前端的校验时弱不禁风的 不能指望他!!  真校验害得靠后端

form表单可以取消浏览器自动添加校验功能的操作:  novalidate属性 
<form action="" method="post" novalidate></form>
'''
前端:
<form action="" method="post" novalidate>
    {% for form in form_obj %}
        <p>
            {{ form.label }}
            {{ form }}
            {{ form.errors.0 }}  # 展示错误信息 固定写法
        </p>
    {% endfor %}
    <input type="submit">
</form>

后端:
def func(request):
    form_obj = MyForm()
    if request.method == 'POST':
        form_obj = MyForm(request.POST)
        if form_obj.is_valid():
            print(form_obj.cleaned_data)
    return render(request,'func.html',locals())

form类重要字段参数

max_length、min_length
max_value、min_value
label					    字段注释
error_messages				 错误提示信息
required					是否为空(是否不传值也能通过校验)
widget						标签类型、标签属性
initial						默认值
validators					正则校验

钩子函数

提供了自定义的校验方式

钩子函数的含义就是在程序的执行过程中穿插额外的逻辑

from类提供第一层校验(格式校验)钩子函数提供第二层校验(如用户名是否存在...)

 '钩子函数在数据经过了字段第一层参数校验之后才会运行'
局部钩子:校验单个字段(用户名是否已存在...)
	def clean_name(self):
        name = self.cleaned_data.get('name')
        res = models.User.objects.filter(name=name).first()
        if res:
        	return self.add_error('name','用户名已存在')
        return name

全局钩子:校验多个字段(两次密码是否一致...)
    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        confirm_pwd = self.cleaned_data.get('confirm_pwd')
        if not pwd == confirm_pwd:
        	return self.add_error('confirm_pwd','两次密码不一致')
        return self.cleaned_data

ModelForm组件

modelform是form的优化版本 使用更简单 功能更强大

class MyModelForm(forms.ModelForm):
    class Meta:
        model = models.User
        fields = '__all__'
    def clean_name(self):
        name = self.cleaned_data.get('name')
        res = models.User.objects.filter(name=name).first()
        if res:
            self.add_error('name','用户名已存在')
        return name