参考:http://www.cnblogs.com/wupeiqi/articles/6144178.html
FORM中的字段只对post上来的数据进行form验证,
主要涉及:字段 和 插件
字段:对用户请求数据的验证。
插件:用于自动生成html。
- 自定义:
- 创建类
- 定义字段(验证)
- 插件(生成html)
- 初始化操作
实例:通过前端html和后台django,通过from实现一个简单的表单验证及多个功能的展示
前端fm.html代码:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {#功能:实现表单进行数据验证,并在验证未通过情况下,页面不进行刷新,只提示错误#} <form action="/fm" method="post"> {% csrf_token %} {# 以下第一个user.label为FM表单user字段的label值,第二个obj.user为FM表单的user字段,最后的一个是FM表单的error_messages错误提醒#} {% csrf_token %} <p> {{ obj.user.label }}{{ obj.user }}{{ obj.errors.user.0 }} </p> <p> {{ obj.pwd.label }}{{ obj.pwd }}{{obj.errors.pwd.0 }} </p> <p> {{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }} </p> <p> {{ obj.f.label }}{{ obj.f }}{{ obj.errors.f.0 }} </p> <p> {# 这个提交的是选中的文件的路径#} {{ obj.p }} </p> <p> {# choice下拉框选项#} {{ obj.cite }} </p> <p> {# 单选#} {{ obj.cite2 }} </p> <p> {{ obj.mcite }} </p> <input type="submit" value="提交" /> </form> </body> </html>
后台代码

from django import forms from django.forms import fields # widgets 插件可以定义html的标签和样式,fields表示字段 from django.forms import widgets class FM(forms.Form): # 这里的各个字段,本身自己只做验证 user = fields.CharField( error_messages={'required':'用户名不能为空'}, # 错误提醒 widget = widgets.Textarea(attrs={'class':'c1','style':'background:#e2e3e4'}), # html标签和样式 label = '用户名', # 标签 #initial='admin', # 定义初始值 ) pwd = fields.CharField( max_length=12, min_length=6, error_messages={'required':'密码不能为空','min_length':'密码最小长度6位','max_length':'密码最大长度为12位'}, widget = widgets.PasswordInput(attrs={'style':'background:#e3e4e5'}), label = '密码', ) email = fields.EmailField( error_messages={'required':'邮箱不可以为空','invalid':'邮箱格式不正确'}, label = '邮箱', ) f = fields.FileField( label='上传文件' ) # 可以显示指定目录下所有的文件 p = fields.FilePathField( path='d:/' ) # 下拉框 cite = fields.ChoiceField( choices=[(0,'bj'),(1,'sh'),(2,'sz')] ) cite2 = fields.CharField( initial=2, widget=widgets.RadioSelect(choices=((0,'man'),(1,'girl'))) ) # 多选下拉框 mcite = fields.MultipleChoiceField( choices=[(0,'bj'),(1,'sh'),(2,'sz')] ) def fm(request): # GET将返回表单输入框 if request.method == 'GET': # 从数据库提取数据,为字段生成默认值,注意必须为字典格式,健必须为FM的字段名 dic = { 'user':'r1', 'pwd':'abc', 'email':'test@test', 'cite':1, 'mcite':[1,2], } obj = FM(initial=dic) # 这里将dic作为参数传入,即可生成默认值 return render(request,'fm.html',{'obj':obj}) if request.method == 'POST': # POST获取所有提交的数据并进行校验(is_valid),cleaned_data以字典格式返回所有校验成功的数据,errors返回所有校验失败的数据, # 直接将obj返回给前端,前端进行错误打印,as_json以json格式打印所有错误 obj = FM(request.POST) ck = obj.is_valid() if ck: print(obj.cleaned_data) # 将表单数据进行数据库添加 models.UserName.objects.create(**obj.cleaned_data) return redirect('/fm') else: print(obj.errors) print(obj.errors.as_json()) return render(request,'fm.html',{'obj':obj})
Form内置字段:
### 字符串验证###
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示),了解
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
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, 小数位长度
### 时间格式验证###3
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
...
### 这个就相当于 CharField + validators ####
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) # URL的正则表达式
...
BooleanField(Field) # 布尔
...
NullBooleanField(BooleanField)
...
### 比较重要######
ChoiceField(Field) # 单选下拉框
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
MultipleChoiceField(ChoiceField) # 多选下拉框
...
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= '' 空值的默认值
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类型
##### 内置插件 ######
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
每个插件内部都可以使用attr自定制属性
实例:通过表单实现单选
forms.py 内容

from django.forms import widgets,fields from django import forms from app01 import models from django.forms.models import ModelChoiceField,ModelMultipleChoiceField # ModelChoiceField 单选 # ModelMultipleChoiceField 多选 class UserInfoForm(forms.Form): user = fields.CharField( required=False, widget = widgets.Textarea(attrs={'class':'c1'}) ) pwd = fields.CharField( max_length=12, widget = widgets.PasswordInput(attrs={'class':'c1'}) ) user_type = fields.ChoiceField( # choices=[(0,'普通用户'),(1,'超级用户')], choices=[], widget=widgets.Select ) user_type2 = fields.CharField( widget=widgets.Select(choices=[]) ) user_type3 = ModelChoiceField( empty_label='请选择用户类型', # 使用此方法虽然不用使用构造方法,但是表需要定制__str__方法 queryset=models.UserType.objects.all(), to_field_name='id' # 生成select标签内option的value值 ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices = models.UserType.objects.values_list('id','name') self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')
views.py内容
def index2(request): from app01.forms import UserInfoForm obj = UserInfoForm() return render(request,'indexform.html',{'obj':obj})
indexform.html内容
<body> <p>{{ obj.user }}</p> <p>{{ obj.pwd }}</p> <p>{{ obj.user_type }}</p> <p>{{ obj.user_type2 }}</p> <p>{{ obj.user_type3 }}</p> </body>
form: 数据验证,经历3个阶段
- 每一个字段(正则,字段钩子)
- clean
- _post_clean
对于错误信息:整体的错误信息放于__all__内。
实例:数据验证,使用钩子
forms.py内容

# 钩子举例,注册,登录 from django.core.exceptions import ValidationError class RegisterForm(forms.Form): '''字段增加验证方式,首先进行user字段的正则表达式验证,如果通过了。然后进行源码里预留的钩子clean_user验证''' user = fields.CharField() email = fields.EmailField() def clean_user(self): '''源码里通过钩子clean+_field,增加正则表达式验证''' c = models.User.objects.filter(name=self.cleaned_data['user']).count() if not c: return self.cleaned_data['user'] else: raise ValidationError('用户名已经存在',code='xxx') def clean_email(self): pass class LoginForm(forms.Form): user = fields.CharField() pwd = fields.CharField(validators=[]) # 这个参数可以自定义正则表达式验证 def clean_user(self): '''第一类钩子字段验证,源码里通过钩子clean+_field,增加正则表达式验证''' c = models.User.objects.filter(name=self.cleaned_data['user']).count() if not c: return self.cleaned_data['user'] else: raise ValidationError('用户名已经存在',code='xxx') def clean_pwd(self): pass def clean(self): '''第二类钩子 整体进行验证''' self.cleaned_data['user'] self.cleaned_data['pwd'] c = models.User.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count() if c: return self.cleaned_data else: raise ValidationError('用户名或密码错误') def _post_clean(self): '''第三类钩子''' pass
views.py 内容
def register(request): from app01.forms import RegisterForm obj = RegisterForm(request.POST) if obj.is_valid(): obj.cleaned_data else: obj.errors