Form组件的简单使用
创建models类
以员工注册为例,创建一个表示员工表的类
models.pyfrom django.db import models# Create your models here.class Emp(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() salary = models.DecimalField(max_digits=8, decimal_places=2)
自定义Form类
在app1下面新建一个py文件
myForm.py(myForm是自己起的名字)from django import formsclass EmpForm(forms.Form): # 这里定义的字段和models里面的Emp表的字段必须一一对应 # label的值为input对应的label标签显示的内容 # error_message:验证未通过时显示的信息 name = forms.CharField(min_length=5, label='姓名', error_messages={ # 键:字段约束,required是form组件自动加的 # 值:验证未通过时显示的错误信息 'required': '姓名不能为空', 'min_length': '姓名至少为5位', }) # 定制约束条件 age = forms.IntegerField(label='年龄') salary = forms.DecimalField(max_digits=5, decimal_places=2, label='工资')
在视图函数里生成form对象并将form对象传给前端
views.py
from django.shortcuts import render, HttpResponse, redirectfrom app1.myForm import EmpFormfrom app1 import models# Create your views here.# 1. 自己写html页面# def login(request):# if request.method == 'POST':# pass# else:# return render(request, 'login.html')# 2. 用form自动生成html页面def login(request): if request.method == 'POST': # 把request.POST作为参数传进去 form = EmpForm(request.POST) # 验证数据 if form.is_valid(): # 打印验证过的数据(可以写进数据库里) print('form.cleaned_data:', form.cleaned_data) models.Emp.objects.create(**form.cleaned_data) else: # 打印错误信息 print('form.errors:', form.errors) return render(request, 'login.html', {'form': form}) else: form = EmpForm() # 实例化一个EmpForm对象 # 把form传给前端页面 return render(request, 'login.html', {'form': form})
在前端页面里用form对象生成html标签
login.html
#}{# 2. aas_p: 一次展示所有字段 #}{# #}{# 4. for循环获取form对象的字段 #} {# 注意:用这种方式生成的input标签会自动加上required属性,也就是不能为空 #}{# 为空时提交不了,浏览器会显示必须填写此字段 #}{# 如果要去掉这个,在form里加上novalidate,告诉浏览器不用验证直接提交(正常期间狂不用加) #}{# 提交验证未通过时,form组件会保留用户输入的信息 #}Title 员工注册
{# 1. 自己写的html页面 #}{#
小结
什么是Form组件?
Form组件就是用一个类来表示form表单,类的属性对应form表单里面的input标签,注意不包括submit按钮
Form组件有哪些作用?
- 页面初始化,生成HTML标签
- 校验用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
局部钩子和全局钩子
局部钩子
什么是局部钩子?
在自定义Form类下面定义一个函数,名字叫:clean_字段名字,内部,取出该字段,进行校验,如果通过,将该字段返回,如果失败,抛出异常(ValidationError)
定义局部钩子
from django import formsfrom django.core.exceptions import ValidationErrorfrom app01 import modelsclass EmpForm(forms.Form): name = forms.CharField(min_length=5, label="姓名", error_messages={ "required": "该字段不能为空!", "min_length": "用户名太短。"}) age = forms.IntegerField(label="年龄") salary = forms.DecimalField(max_digits=5, decimal_places=2, label="工资") # 注意这里函数的名字必须是clean_字段名的形式 def clean_name(self): # 局部钩子 val = self.cleaned_data.get("name") # 如果是数字 if val.isdigit(): # 抛出异常,使用ValidationError之前要导入 raise ValidationError("用户名不能是纯数字") elif models.Emp.objects.filter(name=val): raise ValidationError("用户名已存在!") else: return val姓名输入纯数字时,显示错误信息 输入数据库已存在的姓名时,显示错误信息 输入正确的信息时,正常提交 检查数据库是否写入
全局钩子
什么是全局钩子?
局部钩子只是校验一个字段是否合法,如果要校验不同字段之间的值,需要使用全局钩子,也就是说,全局钩子是校验不同字段之间的一种方法
定义全局钩子
在EmpForm下面添加一个字段r_salary
class EmpForm(forms.Form): # 这里定义的字段和models里面的Emp表的字段必须一一对应 # label的值为input对应的label标签显示的内容 # error_message:验证未通过时显示的信息 name = forms.CharField(min_length=5, label='姓名', error_messages={ # 这里每一个键值对表示对应的字段验证未通过时显示的错误信息 'required': '姓名不同为空', 'min_length': '姓名太短', }) # 定制约束条件 age = forms.IntegerField(label='年龄') salary = forms.DecimalField(max_digits=5, decimal_places=2, label='工资') r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="请再次输入工资")定义clean方法
from django import formsfrom app1 import modelsfrom django.core.exceptions import ValidationErrorclass EmpForm(forms.Form): # 这里定义的字段和models里面的Emp表的字段必须一一对应 # label的值为input对应的label标签显示的内容 # error_message:验证未通过时显示的信息 name = forms.CharField(min_length=5, label='姓名', error_messages={ # 这里每一个键值对表示对应的字段验证未通过时显示的错误信息 'required': '姓名不同为空', 'min_length': '姓名太短', }) # 定制约束条件 age = forms.IntegerField(label='年龄') salary = forms.DecimalField(max_digits=5, decimal_places=2, label='工资') r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="请再次输入工资") def clean_name(self): val = self.cleaned_data.get('name') if val.isdigit(): raise ValidationError('姓名不能不能全是数字') elif models.Emp.objects.filter(name=val): raise ValidationError('用户名已存在') else: return val def clean(self): salary = self.cleaned_data.get('salary') r_salary = self.cleaned_data.get('r_salary') if salary != r_salary: raise ValidationError('工资输入有误') else: return self.cleaned_data修改视图函数
from django.shortcuts import render, HttpResponse, redirectfrom app1.myForm import EmpFormfrom app1 import modelsdef login(request): if request.method == 'POST': # 把request.POST作为参数传进去 form = EmpForm(request.POST) # 验证数据 if form.is_valid(): # 打印验证过的数据(可以写进数据库里) data = form.cleaned_data # 注意一定要删除多余的数据 data.pop('r_salary') models.Emp.objects.create(**data) return Httpresponse('添加成功') else: # 获取全局错误信息 clear_errors = form.errors.get('__all__') return render(request, 'login.html', {'form': form, 'clear_errors': clear_errors}) else: form = EmpForm() # 实例化一个EmpForm对象 # 把form传给前端页面 return render(request, 'login.html', {'form': form})两次工资输入不一致时
小结
- 局部钩子和全局钩子都是用来校验用户输入的数据,校验成功返回对应的值,校验失败主动抛出异常
- 局部钩子用来校验
某个字段
是否合法,着眼于局部;全局钩子用来校验多个字段之间
是否满足某种关系(合法性),着眼于全局 - 局部钩子在前,全局钩子在后