forms组件
forms组件
先抛出一个需求:
1.写一个注册功能,获取用户输入的用户名和密码,提交到后端,后端做校验 2.用户名里面不能含有敏感信息,给出相应的提示 3.如果密码小于三位,就提示用户
手动书写需求
views.py
def register(request): errors = {'username':'', 'password':''} if request.method == 'post': username = request.post.get('username') password = request.post.get('password') if 'zf' in username: errors['username'] = '不能使用该字符' if len(password) < 4: errors['password'] = '密码不能小于三位' return render(request, 'register.html', locals())
register.html
<form action="" method="post"> <p> username:<input type="text" name="username"> <span style="color: red">{{ errors.username }}</span> </p> <p> password:<input type="text" name="password"> <span style="color: red">{{ errors.password }}</span> </p> <input type="submit"> </form>
这里实现了三个功能:
- 手写html页面获取用户输入信息
- 将数据传入后端做数据校验
- 如果有错误,展示错误信息
但是这个页面手写麻烦,输入信息写错了,一刷新信息全没了,很不友好!!
使用forms组件校验数据
使用forms组件首先要导入forms模块, 写这玩意类似于models
from django import forms class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3) # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3) # email字段 必须是邮箱格式 email = forms.emailfield()
然后对数据进行校验, 可以写一个测试脚本,还可以使用pycharm左下角的python console功能,会自动搭建测试脚本
使用测试
校验数据的方法:
-
给写好的类 传字典数据(待校验的数据)
form_obj = views.myform({'username':'cwz','password':'12','email':'123'})
-
如何查看校验的数据是否合法
form_obj.is_valid()
只有全部数据符合校验规则才为true -
如何查看不符合规则的字段及错误的理由
form_obj.errors
-
如何查看符合校验规则的数据
form_obj.cleaned_data
forms组件中 定义的字段默认都是必须传值的 不能少传
forms组件只会校验forms类中定义的字段 如果你多传了 不会有任何影响
forms组件渲染标签
1. 方式一
forms组件只会帮你渲染用户输入的标签,不会帮渲染提交按钮标签。
views.py
def index(request): # 渲染标签,先生成一个空的form类的对象 form_obj = myform() return render(request, 'index.html', locals())
前端页面:
<p>forms组件渲染的方式1</p> {{ form_obj.as_p }} <br> {{ form_obj.as_ul }} <br> {{ form_obj.as_table }}
效果:
总结:这种渲染标签的方式封装程度态高 不推荐使用 但是可以用在本地测试
2. 方式二
不推荐使用,比较麻烦
<p>forms组件渲染标签方式2:</p> {{ form_obj.username.label }}{{ form_obj.username }} {{ form_obj.password.label }}{{ form_obj.password }} {{ form_obj.email.label }}{{ form_obj.email }}
3.方式三
<p>forms组件渲染标签方式3:</p> {% for form in form_obj %} <p>{{ form.label }} {{ form }}</p> {% endfor %}
若想要label标签显示中文,可以指定label标签:
from django import forms class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名') # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3, label='密码') # email字段 必须是邮箱格式 email = forms.emailfield(label='邮箱')
forms组件展示信息
<form action="" method="post"> {% for form in form_obj %} <p>{{ form.label }} {{ form }}</p> {% endfor %} <input type="submit"> </form>
views.py
from django import forms class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名') # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3, label='密码') # email字段 必须是邮箱格式 email = forms.emailfield(label='邮箱') def index(request): # 渲染标签,先生成一个空的forms类的对象 form_obj = myform() if request.method == 'post': form_obj = myform(request.post) if form_obj.is_valid(): print(form_obj.cleaned_data) return httpresponse('数据正确') else: print(form_obj.errors) return render(request, 'index.html', locals())
这玩意是前端做的校验
注意:
数据的校验通常前后端都有,但是前端的校验不堪一击,可有可无;后端的校验必须要有而且必须非常全面
在前端form表单加上一个参数(novalidate),就可以不做校验:<form action="" method="post" novalidate>
前端错误信息展示写法:
<form action="" method="post" novalidate> {% for form in form_obj %} <p>{{ form.label }} {{ form }} <span>{{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit"> </form>
也支持中文显示信息
from django import forms class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名', error_messages={ 'max_length': '用户名最长八位', 'min_length': '用户名最短三位', 'required': '用户名不能为空', }) # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3, label='密码', error_messages={ 'max_length': '密码最长八位', 'min_length': '密码最短三位', 'required': '密码不能为空', }) # email字段 必须是邮箱格式 email = forms.emailfield(label='邮箱', error_messages={ 'required': '邮箱不能为空', 'invalid': '邮箱格式不正确' })
form组件自定义校验
regexvalidator验证器
from django import forms from django.core.validators import regexvalidator class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名', error_messages={ 'max_length': '用户名最长八位', 'min_length': '用户名最短三位', 'required': '用户名不能为空', }) # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3, label='密码', error_messages={ 'max_length': '密码最长八位', 'min_length': '密码最短三位', 'required': '密码不能为空', }, validators=[ regexvalidator(r'^[0-9]+$', '请输入数字'), regexvalidator(r'^139[0-9]+$', '数字必须要以139开头') # 可以添加多个正则表达式,从上往下校验 ] )
钩子函数 (hook)
当你觉得上面的所有校验还是不能满足需求,可以考虑钩子函数
全局钩子
我们在fom类中定义 clean() 方法,就能够实现对字段进行全局校验。
class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名', error_messages={ 'max_length': '用户名最长八位', 'min_length': '用户名最短三位', 'required': '用户名不能为空', }) # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3, label='密码', error_messages={ 'max_length': '密码最长八位', 'min_length': '密码最短三位', 'required': '密码不能为空', }) re_password = forms.charfield(max_length=8, min_length=3, label='确认密码', error_messages={ 'max_length': '确认密码最长八位', 'min_length': '确认密码最短三位', 'required': '确认密码不能为空', }) # 校验密码 确认密码是否一致 def clean(self): password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('password') if not password == re_password: self.add_error('re_password', '两次,密码不一致') return self.cleaned_data
局部钩子
我们在fom类中定义 clean_字段名() 方法,就能够实现对特定字段进行校验。
class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名', error_messages={ 'max_length': '用户名最长八位', 'min_length': '用户名最短三位', 'required': '用户名不能为空', }) # password字段 最多八位, 最少三位 password = forms.charfield(max_length=8, min_length=3, label='密码', error_messages={ 'max_length': '密码最长八位', 'min_length': '密码最短三位', 'required': '密码不能为空', }) re_password = forms.charfield(max_length=8, min_length=3, label='确认密码', error_messages={ 'max_length': '确认密码最长八位', 'min_length': '确认密码最短三位', 'required': '确认密码不能为空', }) # 校验用户名中不能有666 def clean_username(self): username = self.cleaned_data.get('username') if '666' in username: # 给username字段添加错误信息 self.add_error('username', '666是不存在的') # 将username返回出去 return username
forms组件补充知识点
其他字段参数
label input对应的提示信息
initial 默认值
required 默认为true 控制字段是否必填
class myform(forms.form): # username字段 最多八位, 最少三位 username = forms.charfield(max_length=8, min_length=3, label='用户名', initial='默认值', error_messages={ 'max_length': '用户名最长八位', 'min_length': '用户名最短三位', 'required': '用户名不能为空', }, required=false)
widget 给input框设置样式及属性
password = forms.charfield(max_length=8, min_length=3, label='密码', error_messages={ 'max_length': '密码最长八位', 'min_length': '密码最短三位', 'required': '密码不能为空', }, widget=forms.widgets.passwordinput() # 这个password字段是密文的
username = forms.charfield(max_length=8, min_length=3, label='用户名', initial='默认值', error_messages={ 'max_length': '用户名最长八位', 'min_length': '用户名最短三位', 'required': '用户名不能为空', }, required=false, widget=forms.widgets.textinput({'class': 'form-control c1 c2', 'username': 'cwz'}) )
error_messages
重写错误信息。
class loginform(forms.form): username = forms.charfield( min_length=8, label="用户名", initial="张三", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } ) pwd = forms.charfield(min_length=6, label="密码")
password
class loginform(forms.form): ... pwd = forms.charfield( min_length=6, label="密码", widget=forms.widgets.passwordinput(attrs={'class': 'c1'}, render_value=true) )
radioselect
单radio值为字符串
class loginform(forms.form): username = forms.charfield( min_length=8, label="用户名", initial="张三", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } ) pwd = forms.charfield(min_length=6, label="密码") gender = forms.fields.choicefield( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", initial=3, widget=forms.widgets.radioselect() )
单选select
class loginform(forms.form): ... hobby = forms.choicefield( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=3, widget=forms.widgets.select() )
多选select
class loginform(forms.form): ... hobby = forms.multiplechoicefield( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=[1, 3], widget=forms.widgets.selectmultiple() )
单选checkbox
class loginform(forms.form): ... keep = forms.choicefield( label="是否记住密码", initial="checked", widget=forms.widgets.checkboxinput() )
多选checkbox
class loginform(forms.form): ... hobby = forms.multiplechoicefield( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.checkboxselectmultiple() )
choice字段注意事项
在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新
方式一
from django.forms import form from django.forms import widgets from django.forms import fields class myform(form): user = fields.choicefield( # choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.select ) def __init__(self, *args, **kwargs): super(myform,self).__init__(*args, **kwargs) # self.fields['user'].choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].choices = models.classes.objects.all().values_list('id','caption')
方式二
from django import forms from django.forms import fields from django.forms import models as form_model class finfo(forms.form): authors = form_model.modelmultiplechoicefield(queryset=models.nnewtype.objects.all()) # 多选 # authors = form_model.modelchoicefield(queryset=models.nnewtype.objects.all()) # 单选
上一篇: Python—数据类型之列表(List)