form组件简单使用
Forms组件
我们在很多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等是否正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
Django forms组件就实现了上面所述的功能。form组件的主要功能如下:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
基本使用
forms组件在视图层中使用,通常与模型层结合。最简单的使用步骤如下
- 导入forms模块
- 书写forms类
- 像写模型层一样,书写校验字段
- 建立forms对象,字典形式传入要校验的数据
- 执行.is_valid() 方法,对数据进行校验
- 执行其他方法
必须先执行.is_valid(),才可以取cleaned_data和errors
from django import forms
# 导入forms
class RegisterForm(forms.Form):
# 书写字段,和写models几乎一样
account = forms.CharField(min_length=3,max_length=10)
# 最小长度3,最大长度10,当然不止这两个属性
pwd = forms.CharField(min_length=3,max_length=16)
# 在视图函数中使用forms组件
class Register(View):
def get(self, request):
return render(request, 'login_forms.html')
def post(self, request):
user_dic = json.loads(request.body)
print(user_dic)
# 1. 创建forms对象,传入校验数据的字典
form_obj = RegisterForm(user_dic)
# 执行is_valid(),校验数据
print(form_obj.is_valid())
# cleaned_data里面是通过校验的数据
print(form_obj.cleaned_data)
# errors里面是没有通过校验的数据
print(form_obj.errors)
return JsonResponse(user_dic)
# 1 将带校验的数据组织成字典的形式传入即可
form_obj = 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
钩子函数
经过第一层校验之后,如果还有别的需求,需要再进行校验,如:字段是否已经存在数据库、两次输入密码是否一致、是否包含敏感词,可以把这些自定义的校验写在钩子函数里,再进行第二次校验
钩子函数分为局部钩子和全局钩子,局部钩子只校验单一字段的数据,全局钩子可以校验所有字段的数据。
像别的钩子函数一样,校验完之后要return校验的数据
基本写法
在上面创建的forms类下写函数,针对已经创建的字段,forms会帮你生成方法,pycharm中可以看到代码提示
局部钩子
def clean_account(self):
# clean_要勾出来的字段名,表示对这个字段使用局部钩子
account = self.cleaned_data.get('account')
# 因为到达钩子函数的数据,已经经过了第一层校验,所以在clean_data里面用get取值
if '自由' in account:
self.add_error('account','人民不需要自由')
# 自己写一些逻辑
# add_errror('字段名','错误信息')
# 可以手动写错误信息
return account
# 最后要把数据return回去
全局钩子
# 固定写法了
def clean(self):
# clean就是全局钩子
pwd = self.cleaned_data.get('pwd')
pwd_confirm = self.cleaned_data.get('pwd_confirm')
# 因为到达钩子函数的数据,已经经过了第一层校验,所以在clean_data里面用get取值
if not pwd == pwd_confirm:
self.add_error('pwd_confirm','两次输入密码不一致')
# 自己写逻辑
return self.cleaned_data
# 把整个clean_data还回去
内置字段
看看就好,用的上的复制走
Field
required=True, 是否允许为空,默认不允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值,相当于html的value
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
BaseTemporalField(Field)
input_formats=None 时间格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
渲染标签
三种渲染方式,但是只用在前后端不分离的项目上
方式一
from django import forms # 引入forms组件
class UserForm(forms.Form): # 必须继承forms.Form
# forms.CharField和forms.EmailField会渲染为input标签
name = forms.CharField(min_length=4) # 默认label是字段名
pwd = forms.CharField(min_length=4, label="密码") # 如果需要中文label可以手动设置
r_pwd = forms.CharField(min_length=4, label="确认密码")
email = forms.EmailField(label="邮箱")
tel = forms.CharField(label="手机")
def reg(request):
form = UserForm()
return render(request, "reg.html", locals())
<h3>form组件渲染方式1</h3>
<form action="" method="post">
{% csrf_token %}
<p>{{ form.name.label }}
{{ form.name }}
</p>
<p>{{ form.pwd.label }}
{{ form.pwd }}
</p>
<p>{{ form.r_pwd.label }}
{{ form.r_pwd }}
</p>
<p>{{ form.email.label }}
{{ form.email }}
</p>
<p>{{ form.tel.label }}
{{ form.tel }}
</p>
<input type="submit">
</form>
方式二
同理方式一,只是用了for循环
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<p>
<label for="">{{ field.label }}</label>
{{ field }}
</p>
{% endfor %}
<input type="submit">
</form>