1、forms组件的使用
#1、导入forms模块
from django import forms
#2、创建forms类,继承forms.Form
class Forms(forms.Form):
username=forms.CharField(min_length=3,max_length=8,label='用户名'})
password=forms.CharField(min_length=3,max_length=8,label='密 码'})
email=forms.EmailField(label='邮 箱'})
#3、在views视图函数中实例化该Forms对象,前端就可以直接渲染使用
def forms(request):
form_obj=Forms()
return render(request,'forms.html',locals())
2、forms组件的渲染
<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.value }}{{ form_obj.password }}</p>
<p>第三种渲染方式:推荐使用</p>
{% for form in form_obj %}
<p>{{ form.label }}:{{ form}}</p>
{% endfor %}
3、fomrs组件的校验
form_obj=views.Forms({'username':'json','password':'123','email':'123','age':'hello'})
form_obj.errors
>>{'email': ['邮箱格式不对']}
form_obj.is_valid()
>>False
form_obj=views.Forms({'username':'json','password':'123','email':'123@qq.com','age':'hello'})
form_obj.is_valid()
>>True
form_obj.errors
>>{}
form_obj=views.Forms({'username':'json','password':'123'})
#判断校验是否通过
form_obj.is_valid()
>>False
#查看校验不通过数据的原因
form_obj.errors
>>{'email': ['邮箱不能为空']}
#查看所有校验通过的数据
form_obj.cleaned_data
>>{'username': 'json', 'password': '123'}
'''
总结:1、form数据校验的时候,多传字段,不会有影响,它只会校验我设置的字段,其他字段不校验
2、form数据校验不能少传字段,否则校验结果为false
3、form校验通过的数据会放在cleaned_data中,不通过的数据会放在errors
'''
4、forms组件错误信息的展示
#前端代码
#novalidate参数是让浏览器不做数据校验
<form action="" method="post" novalidate>{% csrf_token %}
<p>第三种渲染方式:推荐使用</p>
{% for form in form_obj %}
<p>{{ form.label }}:{{ form}}
#因为form.errors获取的结果是一个列表形式,为了避免errors被解析成li标签,在这里加.0直接那列表里的值
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit" class="btn btn-info" value="提交">
</form>
class Forms(forms.Form):
'''
自定义标签名、error_messages错误信息
'''
username=forms.CharField(min_length=3,max_length=8,label='用户名',
error_messages={
'min_length':'用户名长度至少为3位',
'max_length':'用户名长度不能超过8位',
'required':'用户名不能为空',
})
password=forms.CharField(min_length=3,max_length=8,label='密 码',
error_messages={
'min_length': '密码长度至少为3位',
'max_length': '密码长度不能超过8位',
'required': '密码不能为空',
})
email=forms.EmailField(label='邮 箱',
error_messages={
'required':'邮箱不能为空',
'invalid':'邮箱格式不对'
})
def forms(request):
form_obj=Forms()
if request.method=='POST':
form_obj=Forms(request.POST)
if form_obj.is_valid():
return HttpResponse('注册成功')
return render(request,'forms.html',locals())
'''
总结:注意get\post请求中两个form_obj对象名必须保持一致,这样出现错误的时候,会保留之前的数据。
'''
5、forms组件中钩子函数
钩子函数实质:就是将数据拿出来校验,校验完后再放回去
钩子函数分为:局部钩子函数和全局钩子函数
局部钩子函数:主要用来对特定字段进行校验, 函数名为:clean_字段名()
全局钩子函数:主要用来对全局字段进行校验,也就是多个字段校验 函数名为:clean()
#局部钩子函数,用来校验单个字段
def clean_username(self):
username=self.cleaned_data.get('username')
if 'NQ' in username:
#add_error方法第一参数放校验字段,第二参数放错误提示信息
self.add_error('username','用户名不能有NQ')
#将数据归还回去
return username
#全局钩子函数
def clean(self):
passwd=self.cleaned_data.get('password')
comfirm=self.cleaned_data.get('comfirm')
if passwd !=comfirm:
self.add_error('comfirm','密码不一致')
#全局钩子拿到的数据是全部,所以这里要将全部数据归还回去
return self.cleaned_data
'''
注意:校验完后,数据一定要归还
'''
Forms组件常用的字段
initial:input框中的初始值,类似于form表单中value
error_messages:自定义错误信息
widget:输入框的类型,以及样式自定义
- render_value:如果render_value=True会将出错数据跟错误信息返回,False只返回错误信息
- attrs:用来存放html标签的属性,以字典的形式,如设置class属性:attrs={'class'='c1 c2'},
password输入框类型
password=forms.CharField(min_length=3,max_length=8,label='密 码',
error_messages={
'min_length': '密码长度至少为3位',
'max_length': '密码长度不能超过8位',
'required': '密码不能为空',},
widget=forms.widgets.PasswordInput(attrs={'class':'form_control'},render_value=True)
)
radioSelect(单选按钮类型)
gender = forms.fields.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()
)
多选Select(多选下拉框)
hobby = 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(多选复选框)
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
注意:choice字段从数据库中获取的时候,获取的值是无法实时更新的,需要我们重写构造方法来实现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()) # 单选
Django Form所有内置字段
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
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
DurationField(Field) 时间间隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否允许空文件
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值
ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) uuid类型
字段校验
RegexValidator验证器,放在字段中validators自定义校验 规则参数中
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
自定义函数:跟上面验证器使用方法一致,也是放在字段中validators自定义校验 规则参数中,只不过是需要自己事先写一个自定义验证规则函数。
import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
# 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
class PublishForm(Form):
title = fields.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': '标题5-20个字符'}))
# 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
email = fields.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))