Django——form表单验证(创建,内置字段,自定义异常,form表单的前端数据实时更新)
Form表单验证
1、创建Form类
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 5 class FM(Form): 6 user = fields.CharField( 7 error_messages={'required':'用户名不能为空'} 8 ) 9 pwd = fields.CharField( 10 max_length=18, 11 min_length=9, 12 error_messages={'required':'密码不能为空','max_length':'密码长度不能大于12','min_length':'密码长度不能小于6'}, 13 widget=widgets.PasswordInput(attrs={'class':'c1','id':'i1'}) 14 ) 15 email = fields.EmailField( 16 error_messages={'required': '邮箱不能为空.', 'invalid': "邮箱格式错误"} 17 ) 18 gender = fields.ChoiceField( 19 choices=((1,'男'),(2,'女'),), 20 initial = 2, #默认值 21 # widget=widgets.Select 22 widget=widgets.RadioSelect 23 ) 24 city = fields.CharField( 25 initial=2, 26 widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) 27 ) 28 abc = fields.MultipleChoiceField( 29 choices=((1,'a'),(2,'b'),(3,'c'),(4,'d')), 30 initial=[1,2], 31 widget = widgets.CheckboxSelectMultiple 32 )
2、views函数处理
1 def form(request): 2 if request.method == 'GET': 3 obj = FM() 4 return render(request,'form.html',{'obj':obj}) 5 elif request.method == 'POST': 6 obj = FM(request.POST) 7 if obj.is_valid(): 8 values = obj.clean() 9 print(values) 10 else: 11 errors = obj.errors 12 print(errors) 13 return render(request,'form.html',{'obj':obj})
3、html页面
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form method="post" action="#"> 9 {% csrf_token %} 10 <p>{{ obj.user }}{{ obj.user.errors.0 }}</p> 11 <p>{{ obj.pwd }}{{ obj.pwd.errors.0 }}</p> 12 <p>{{ obj.email }}{{ obj.email.errors.0 }}</p> 13 <p>{{ obj.city }}{{ obj.city.errors.0 }}</p> 14 <p>{{ obj.gender }}{{ obj.gender.errors.0 }}</p> 15 <p>{{ obj.abc }}{{ obj.abc.errors.0 }}</p> 16 <input type="submit" value="提交"> 17 </form> 18 </body> 19 </html>
Form内置字段
内置字段 --> username = field.CharField(里面写方法)
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, 小数位长度 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类型 ...
内置插件
1 TextInput(Input) 2 NumberInput(TextInput) 3 EmailInput(TextInput) 4 URLInput(TextInput) 5 PasswordInput(TextInput) 6 HiddenInput(TextInput) 7 Textarea(Widget) 8 DateInput(DateTimeBaseInput) 9 DateTimeInput(DateTimeBaseInput) 10 TimeInput(DateTimeBaseInput) 11 CheckboxInput 12 Select 13 NullBooleanSelect 14 SelectMultiple 15 RadioSelect 16 CheckboxSelectMultiple 17 FileInput 18 ClearableFileInput 19 MultipleHiddenInput 20 SplitDateTimeWidget 21 SplitHiddenDateTimeWidget 22 SelectDateWidget
常用选择插件
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 单radio,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 单select,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多选select,值为列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 单checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多选checkbox,值为列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
初始化数据(编辑时,显示之前的数据)
views端:
class FM(Form): form类 ... from app01 import models def fm(request): if request.method == "GET": # 从数据库中吧数据获取到 dic = { "user": 'r1', 'pwd': '123123', 'email': 'sdfsd', 'city1': 1, 'city2': [1,2] } obj = FM(initial=dic) return render(request,'fm.html',{'obj': obj}) elif request.method == "POST": # 获取用户所有数据 # 每条数据请求的验证 # 成功:获取所有的正确的信息 # 失败:显示错误信息 obj = FM(request.POST) r1 = obj.is_valid() if r1: # obj.cleaned_data models.UserInf.objects.create(**obj.cleaned_data) else: # ErrorDict # print(obj.errors.as_json()) # print(obj.errors['user'][0]) return render(request,'fm.html', {'obj': obj}) return render(request,'fm.html')
html端
1 <form method="POST" enctype="multipart/form-data"> 2 {% csrf_token %} 3 <p>{{ form.user }} {{ form.user.errors }}</p> 4 <p>{{ form.city }} {{ form.city.errors }}</p> 5 6 <input type="submit"/> 7 </form>
自定义异常
a.clean_%s(self) #clean_ + 要审查的那个字段
源代码:
实现
b._post_clean(self) # 重写clean方法
源代码
实现
c.clean(self) # 重写clean方法
源代码
实现
1 views.py 2 3 from django.shortcuts import render,redirect,HttpResponse 4 5 from cmdb import models 6 from django import forms 7 from django.forms import fields 8 from django.core.exceptions import ValidationError 9 10 class UserForm(forms.Form): 11 username = fields.CharField(label='用户名') 12 email = fields.EmailField(label='email') 13 14 user_type = fields.ChoiceField(choices=models.UserType.objects.values_list('id', 'name')) 15 16 def clean_username(self): 17 # 自定义错误验证-->验证单个 18 value = self.cleaned_data['username'] 19 if value == 'root': 20 return value 21 else: 22 raise ValidationError('用户名输入错误') 23 24 def _post_clean(self): 25 # 自定义错误验证-->验证多个 26 v1 = value = self.cleaned_data['username'] 27 v2 = value = self.cleaned_data['email'] 28 if v1 == 'root' and v2 == 'alex@163.com': 29 pass 30 else: 31 self.add_error('__all__',ValidationError('用户名或邮箱输入错误')) 32 33 def clean(self): 34 v1 = value = self.cleaned_data['username'] 35 v2 = value = self.cleaned_data['email'] 36 if v1 == 'root' and v2 == 'alex@163.com': 37 pass 38 else: 39 raise ValidationError('用户名或邮箱输入错误') 40 41 42 43 def index(request): 44 if request.method == 'GET': 45 obj = UserForm() 46 return render(request,'index.html',{'obj':obj}) 47 elif request.method == 'POST': 48 obj = UserForm(request.POST) 49 print(obj.is_valid()) 50 # print(obj.clean()) 51 print(obj.cleaned_data) 52 print(obj.errors) 53 return render(request, 'index.html', {'obj': obj}) 54 55 56 index.html 57 58 <!DOCTYPE html> 59 <html lang="en"> 60 <head> 61 <meta charset="UTF-8"> 62 <title>Title</title> 63 </head> 64 <body> 65 <form action="/index/" method="post"> 66 {% csrf_token %} 67 {{ obj.as_p }} 68 <input type="submit" value="提交" /> 69 </form> 70 </body> 71 </html>
保持发送到前端的数据实时更新 # {{ obj.as_p }} {{ obj.name }} {{ obj.name.errors.0 }}
方法一:重写构造函数
1 from django import forms 2 from django.forms import fields 3 4 class UserForm(forms.Form): 5 username = fields.CharField(label='用户名') 6 email = fields.EmailField(label='email') 7 8 user_type1 = fields.ChoiceField(choices=models.UserType.objects.values_list('id', 'name')) 9 10 def __init__(self,*args,**kwargs): 11 super(UserForm,self).__init__(*args,**kwargs) 12 self.fields['user_type1'].widget.choices = models.UserType.objects.all().values_list('id', 'name')
方法二:使用ModelChoiceField # 要在要调用的model写上def__str__:self.xxx
里面可以加的参数
1 class UserForm(forms.Form): 2 username = fields.CharField(label='用户名') 3 email = fields.EmailField(label='email') 4 5 from django.forms import models as models_fields 6 7 user_type2 = models_fields.ModelChoiceField(queryset=models.UserType.objects.all(), 8 empty_label='请选择用户类型', 9 to_field_name="id", 10 limit_choices_to={'id': 1})