python-django_form组件校验数据功能_渲染页码功能_渲染错误信息_组件参数配置_局部钩子和全局钩子

Django Form组件

1. Form基础

1. forms组件介绍

1. 注册功能,登录功能,前端需要校验(字段长度,邮箱是否合法。。。)
2. 前端校验可以没有,后端校验是必须的,使用传统方式  if判断写的很多
3. 借助于forms组件,可以快速实现字段的校验
	from django.forms import Form
1. 示例
"""
写一个注册功能
	获取用户名和密码 利用form表单提交数据
	在后端判断用户名和密码是否符合一定的条件
		用户名中不能含有金瓶梅
		密码不能少于三位
	
	如何符合条件需要你将提示信息展示到前端页面
"""
def ab_form(request):
    back_dic = {'username':'','password':''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '金瓶梅' in username:
            back_dic['username'] = '不符合社会主义核心价值观'
        if len(password) < 3:
            back_dic['password'] = '不能太短 不好!'
    """
    无论是post请求还是get请求
    页面都能够获取到字典 只不过get请求来的时候 字典值都是空的
    而post请求来之后 字典可能有值
    """
    return render(request,'ab_form.html',locals())

<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        <span style="color: red">{{ back_dic.username }}</span>
    </p>
    <p>password:
        <input type="text" name="password">
        <span style="color: red">{{ back_dic.password }}</span>
    </p>
    <input type="submit" class="btn btn-info">
</form>

"""
1. 手动书写前端获取用户数据的html代码		渲染html代码
2. 后端对用户数据进行校验				   校验数据
3. 对不符合要求的数据进行前端提示			展示提示信息

forms组件
	能够完成的事情
			1.渲染html代码
			2.校验数据
			3.展示提示信息

为什么数据校验非要去后端 不能在前端利用js直接完成呢?
	数据校验前端可有可无
	但是后端必须要有!
	
	因为前端的校验是弱不禁风的 你可以直接修改
	或者利用爬虫程序绕过前端页面直接朝后端提交数据
	
	购物网站	
		选取了货物之后 会计算一个价格发送给后端 如果后端不做价格的校验
		
		实际是获取到用户选择的所有商品的主键值
		然后在后端查询出所有商品的价格 再次计算一遍
		如果跟前端一致 那么完成支付如果不一致直接拒绝
"""
2. 基本使用
from django import forms

class MyForm(forms.Form):
    # username字符串类型最小3位最大8位
    username = forms.CharField(min_length=3,max_length=8)
    # password字符串类型最小3位最大8位
    password = forms.CharField(min_length=3,max_length=8)
    # email字段必须符合邮箱格式  xxx@xx.com
    email = forms.EmailField()
3. 校验数据
"""
1. 测试环境的准备 可以自己拷贝代码准备
2. 其实在pycharm里面已经帮你准备一个测试环境
	  python console
"""
from app01 import views
# 1 将带校验的数据组织成字典的形式传入即可
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
# 2 判断数据是否合法	注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()
False
# 3 查看所有校验通过的数据
form_obj.cleaned_data
{'username': 'jason', 'password': '123'}
# 4 查看所有不符合校验规则以及不符合的原因
form_obj.errors
{
  'email': ['Enter a valid email address.']
}
# 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid()
True
# 6 校验数据 默认情况下 类里面所有的字段都必须传值
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()
False
"""
也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传
"""
4. 渲染标签
"""
forms组件只会自动帮你渲染获取用户输入的标签(input select radio checkbox)
不能帮你渲染提交按钮
"""
def index(request):
    # 1 先产生一个空对象
    form_obj = MyForm()
    # 2 直接将该空对象传递给html页面
    return render(request,'index.html',locals())

# 前端利用空对象做操作
    <p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>
    {{ form_obj.as_p }}
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
    
    <p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多  一般情况下不用</p>
    <p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
    <p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
    <p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>
        
    <p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
    {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}</p>
    {% endfor %}
 
"""
label属性默认展示的是类中定义的字段首字母大写的形式
也可以自己修改 直接给字段对象加label属性即可
	 username = forms.CharField(min_length=3,max_length=8,label='用户名')
"""

2. forms校验字段功能

# 1 写一个类,类里写要校验的字段
class MyForm(forms.Form):
    # 校验这个字段,最大长度是32,最小长度是3
    name = forms.CharField(required=False, max_length=32, min_length=3,label='用户名')
    email = forms.EmailField(label='邮箱')
    age=forms.IntegerField(max_value=200,min_value=0,label='年龄')
    
    
# 2 视图函数中使用
def register(request):
    # 数据可以是从前端传过来的,也可以是自己后台的数据

    # 现在有以下数据
    data={'name':'lqz','email':'33333@qq.com','age':900}
    # data={'email':'33333@qq.com','age':100}
    # data={'age':100}
    # 校验数据是否合法
    # 实例化得到form对象,把要校验的数据传入
    form=myforms.MyForm(data)
    # 校验数据:form.is_valid() 返回布尔类型

    if form.is_valid():
        print('校验通过')
        # 校验通过的数据
        print(form.cleaned_data)  # 不一定是上面传入的数据
    else:
        print(form.cleaned_data)
        print('校验失败')
        # 哪个字段失败了?失败的原因是什么
        print(form.errors)
        print(type(form.errors))
        from django.forms.utils import ErrorDict
        # 重写了__str__
        print(form.errors.as_json())
        print(form.errors.as_data())
        # form.errors.as_ul()  # 是为了渲染模板

    return HttpResponse('ok')

3. forms渲染模板功能

1. 视图
# 视图函数
def register(request):
    if request.method=='GET':
        form=myforms.MyForm()
        return render(request,'register.html',{'form':form})
    elif request.method=='POST':
        # 数据校验
        form=myforms.MyForm(request.POST)
        if form.is_valid():
            print('校验通过,存数据库')
        else:
            print(form.errors.as_data())
            print('校验失败,返回错误')
        return HttpResponse('ok')
2. 模板
# 模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    
<hr>
<h1>手动创建模板</h1>
<form action="" method="post">
    <p>用户名:<input type="text" name="name"></p>
    <p>邮箱:<input type="text" name="email"></p>
    <p>年龄:<input type="text" name="age"></p>
    <p><input type="submit" value="提交"></p>
</form>

<hr>
<h1>半自动渲染模板1</h1>
<form action="" method="post">
    <p>用户名:{{ form.name }}</p>
    <p>邮箱:{{ form.email }}</p>
    <p>年龄:{{ form.age }}</p>
    <p><input type="submit" value="提交"></p>
</form>

<h1>半自动渲染模板2(用的最多)</h1>
<form action="" method="post">
    <p>{{ form.name.label }}--{{ form.name }}</p>
    <p>{{ form.email.label }}---{{ form.email }}</p>
    <p>{{ form.age.label }}---{{ form.age }}</p>
    <p><input type="submit" value="提交"></p>
</form>

<h1>半自动渲染模板3(用的最多)</h1>
<form action="" method="post">
    {% for foo in form %}
       <p>{{ foo.label }} :{{ foo }}</p>
    {% endfor %}

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

<h1>全自动(了解)</h1>
<form action="" method="post">
{#    {{ form.as_ul }}#}
    {{ form.as_p }}
{#    <table>#}
{#        {{ form.as_table }}#}
{#    </table>#}

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

2. Form进阶

1. froms渲染错误信息

1. form对象.errors 字典
2. name对象.errors

"""
浏览器会自动帮你校验数据 但是前端的校验弱不禁风
如何让浏览器不做校验: 设置 novalidate 
	<form action="" method="post" novalidate>
"""

# 视图函数
def register(request):
    if request.method=='GET':
        # 1. 先产生一个空对象
        form=myforms.MyForm()
        # 2. 直接将该空对象传递给html页面
        return render(request, 'register.html',{'form':form})
    else:
        # 获取用户数据并且校验
        """
        1. 数据获取繁琐
        2. 校验数据需要构造成字典的格式传入才行
        ps: 但是request.POST可以看成就是一个字典
        """
        # 3. 校验数据
        form=myforms.MyForm(request.POST)
        # 4. 判断数据是否合法
        if form.is_valid():
            # 5. 如果合法 操作数据库存储数据
            return redirect('http://www.baidu.com')
        else:
            # 6. 不合法 返回给注册页面 展示错误信息
            return render(request, 'register.html',{'form':form})

# 模板
<form action="" method="post" novalidate>
	{% for foo in form %}
	<div class="form-group">
        <label for="">{{ foo.label }}</label>
            {{ foo }}
            <span class="text-danger pull-right">{{ foo.errors }}</span>
        </div>
	{% endfor %}
	<div class="text-center">
		<input type="submit" value="提交" class="btn btn-danger">
	</div>
</form>

"""
1. 必备的条件 get请求和post传给html页面对象变量名必须一样
2. forms组件当你的数据不合法的情况下 会保存你上次的数据 
   让你基于之前的结果进行修改更加的人性化
"""

2. forms组件参数配置

# 定制模板中的显示样式及配置类
	widget=widgets.PasswordInput(attrs={'class': 'form-control'})

# 错误信息中文显示
	error_messages={'min_length': '太短了小伙子'}
    
# 示例
class MyForm(forms.Form):
    # 校验这个字段,最大长度是32,最小长度是3
    name = forms.CharField(
        required=False, max_length=32, min_length=3, label='用户名',
        widget = widgets.TextInput(attrs={'class': 'form-control'}),
        error_messages = {'min_length': '太短了小伙子'} 
    )
    
    password = forms.CharField(
        required=False, max_length=32, min_length=3, label='密码',
        widget = widgets.PasswordInput(attrs={'class': 'form-control'}),
        error_messages = {'min_length': '太短了小伙子'}
    )
    
    re_password = forms.CharField(
        required=False, max_length=32, min_length=3, label='确认密码',
        widget = widgets.PasswordInput(attrs={'class': 'form-control'}),
        error_messages = {'min_length': '太短了小伙子'}
    )
    
    email = forms.EmailField(
        label='邮箱', error_messages={'required': '小伙子,这个必填'},
        widget = widgets.TextInput(attrs={'class': 'form-control'})
    )
    
    age = forms.IntegerField(
        max_value=200, min_value=0, label='年龄',
        widget = widgets.TextInput(attrs={'class': 'form-control'})
    )
    
    text = forms.CharField(
        label='个人简介',
        widget = widgets.Textarea(attrs={'class': 'form-control'})
    )
    
    date = forms.CharField(
        label='出生日期', 
        widget = widgets.DateInput(attrs={'class': 'form-control'})
    )

# forms组件其他参数及补充知识点  
    label		    字段名
    error_messages  自定义报错信息
    initial         默认值
    required        控制字段是否必填

"""
1. 字段没有样式
2. 针对不同类型的input如何修改
        text
        password
        date
        radio
        checkbox
        ...
"""  

# 多个属性值的话 直接空格隔开即可
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})

# 第一道关卡里面还支持正则校验
validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字'),
            RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
        ]

3. 定制错误提示信息

# 针对错误的提示信息还可以自己自定制
class MyForm(forms.Form):
    # username字符串类型最小3位最大8位
    username = forms.CharField(min_length=3,max_length=8,label='用户名',
                               error_messages={
                                   'min_length':'用户名最少3位',
                                   'max_length':'用户名最大8位',
                                   'required':"用户名不能为空"
                               }
                               )
    # password字符串类型最小3位最大8位
    password = forms.CharField(min_length=3,max_length=8,label='密码',
                               error_messages={
                                   'min_length': '密码最少3位',
                                   'max_length': '密码最大8位',
                                   'required': "密码不能为空"
                               }
                               )
    # email字段必须符合邮箱格式  xxx@xx.com
    email = forms.EmailField(label='邮箱',
                             error_messages={
                                 'invalid':'邮箱格式不正确',
                                 'required': "邮箱不能为空"
                             }
                             )

4. forms其他类型渲染

# radio
    gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )
    
# select
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )
    
# 多选
    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
    
# 单选checkbox
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
    
# 多选checkbox
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

5. 钩子函数(HOOK)

1. 简介
# 简介
	在特定的节点自动触发完成响应操作
	钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则

# 在forms组件中有两类钩子
	1. 局部钩子
		当你需要给单个字段增加校验规则的时候可以使用
	2. 全局钩子
  		当你需要给多个字段增加校验规则的时候可以使用
        
# 实际案例
	1. 局部钩子
    	校验用户名中不能含有666  只是校验username字段  
	2. 全局钩子     
    	校验密码和确认密码是否一致  校验password confirm两个字段	
2. 局部钩子
# 局部钩子的使用
    1. 在自定义的Form类中写  clean_字段名
    2. 取出字段的真正值      name=self.cleaned_data.get('name')
    3. 判断自己的规则 如果判断失败 抛出异常 ValidationError
    4. 如果通过  return name
    
# 局部钩子
    def clean_name(self):
        # 获取到用户名: name对应的值
        name = self.cleaned_data.get('name')
        if name.startswith('sb'):
            # 不让校验通过 提示前端展示错误信息
            raise ValidationError('不能以sb开头')
        else:
            # 校验通过,返回name (将钩子函数钩出来的数据再返回去)
            return name
3. 全局钩子
# 全局钩子
	# 示例一
    def clean(self):
        # name=self.cleaned_data.get('name')
        # print(name)
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')
        if password == re_password:
            return self.cleaned_data
            # return {'lqz':"nb"}
        else:
            raise ValidationError('两次密码不一致')

	# 示例二
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not confirm_password == password:
            self.add_error('confirm_password','两次密码不一致')
        # 将钩子函数钩出来的数据再放回去
        return self.cleaned_data
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I believe I can fly~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值