1.form组件的主要功能
生成页面的HTML标签和样式 ,将前端form表单的代码放在后端生成!!
对用户提交的数据进行校验(正则)
自动生成错误信息
保留上次输入信息
2.form组件常用字段与插件
字段属性是对用户请求的验证
插件是对生成的HTML标签增加属性
#常用字段的通用属性 required=True #是否可以为空 widget=None #HTML插件 label=None #生成标签的label initial=None #初始值 error_messages=None #错误信息定义 disabled=False #是否可编辑 help_text='' #帮助提示 #常用的字段 CharField(Field) #input标签输入框 max_length=None #最大长度 min_length=None #最小长度 strip=True #是否移除前后空格 #widget=forms.widgets.TextInput(attrs{'class':'bootstrap类'}) #直接改变生成的标签的属性
#widget=forms.widgets.PasswordInput(attrs={'class':'bootstrap类'}) #基于password的密文输入框
ChoiceField(Field) #单选字段(通过插件修改样式) choices=((0,'上海'),(1,'北京')) #前后端对应数据选择 widget=forms.widgets.RadioSelect() #基于input标签的圆形单选 #widget=forms.widgets.CheckboxInput() #基于input标签的方形单选 #widget=forms.widgets.Select() #基于select标签的下拉单选 MultipleChoiceField(ChoiceField) #多选字段(通过插件修改样式) choices=((0,'上海'),(1,'北京')) widget=forms.widgets.SelectMultiple() #基于select的标签完成多选 #widget=forms.widgets.ChecknoxSelectMultiple() #基于inpu标签的方形多选
3.form组件简单使用
1)定义一个form组件的类 ,关键部分:
widget=form.TextInput(attrs={字典}) #插件可以定义标签的类型 ,attrs这个字典可以定义标签属性(增加bootstrap样式!)
error_messages={字典} #字段校验提示信息自定义 ,配合is_valid()使用!
choices #动态获取数据库数据 ,不要在类中写死 ,使用的是重写init方法 ,把fields字段的choices拿出来指定为数据库的值(后端 ,前端显示)
2)定义视图函数 ,将form的对象传到模板 ,关键部分:
get请求中 ,直接将form对象传给模板
post请求中, 需要重新实例化form对象 ,将返回的POST数据作为参数 ,is_vaild()校验, 其中内置的校验如required ,min_length等等字段 ,如果满足继续执行代码 ,不满足将添加了error信息的form对象传给模板(当然这种内置的字段无法满足一些要求)
3)定义模板 ,直接将form对象循环取出展示标签即可 ,关键部分:
label标签是比较重要的需要给对象中每个field设置
4)重写init方法
完成了choices从数据库中动态获取显示内容和后端内容
完成了所有输入框字段的标签,加入了bootstrap样式
#url
url(r'log/', views.log, name='log'),
#view
class LoginForm(forms.Form):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.fields['book'].choices = models.Book.objects.all().values_list('pk', 'name')
# 取出字典中的key遍历
for field in iter(self.fields):
if field != 'book':
self.fields[field].widget.attrs.update({'class': 'form-control'})
user = forms.CharField(
label='用户名',
required=True,
help_text='请在此处输入用户名!',
strip=True,
widget=forms.TextInput(),
)
password = forms.CharField(
label='密码',
required=True,
min_length=6,
error_messages={'required': '必须输入', 'min_length': '最小长度6位'},
widget=forms.PasswordInput()
)
book = forms.MultipleChoiceField(
label='书籍',
# choices=((0, '男'), (1, '女')),
initial=[11],
widget=forms.widgets.CheckboxSelectMultiple(),
)
def log(request):
form_obj = LoginForm()
if request.method == 'POST':
form_obj = LoginForm(request.POST)
if form_obj.is_valid():
name = request.POST.get('user')
password = request.POST.get('password')
print(form_obj.errors)
return render(request, 'formtest.html', {'form_obj': form_obj})
#html
{% extends 'base.html' %}
{% block body1 %}
<form class="form-horizontal" method="post" novalidate>
{% csrf_token %}
{% for field in form_obj %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{{ field.errors.0 }}
</div>
{% endfor %}
<button class="btn" type="submit">提交</button>
</form>
{% endblock %}
4.form表单的数据验证方式
1)内置简单校验
通过属性实现 min_length required等等
2)内置的正则验证 ,自定义正则表达式对字段的返回值进行校验!
导入RegexValidator方法
validators=[RegexValidator(正则 ,错误提示)]
from django.core.validators import RegexValidator .... #对email字段进行正则 email = forms.CharField( label='邮箱', validators=[RegexValidator(r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(.[a-zA-Z0-9-]+)*.[a-zA-Z0-9]{2,6}$', '邮箱格式错误')], widget=forms.TextInput(), ) ....
3)自定义方法验证 (可以应用到非法字符的校验)
导入ValidationError异常处理
写一个校验函数 ,不写return ,不满足要求raise出一个validationError的异常
validators=[函数]
from django.core.exceptions import ValidationError #不满足校验抛异常 def Desc_Valid(value): if 'cnm' in value: raise ValidationError('非法字符') #字段校验器指定函数 ... desc = forms.CharField( label='描述', widget=forms.TextInput(), validators=[Desc_Valid] ) ...
5.源码解读is_valid() ,如何完成数据有效校验
value通过内置校验 ,自定义校验
value通过了局部钩子校验 ,类中自定义的clean_%s的方法
value通过了全局钩子校验 ,类中重写clean()方法 (可以用于多字段联合校验 ,如密码的二次确认)
clean()方法重写如果校验失败就个体一个fields添加一个errormessage ,raise一个异常 校验通过返回self中的原值cleand_data字典
def clean(self): pwd = self.cleaned_data['password'] repwd = self.cleaned_data['repassword'] if pwd != repwd: # 给某个fields添加错误提示 self.add_error('repassword', '密码不一致o') # 异常处理给error raise ValidationError('密码不一致') return self.cleaned_data