Form详解
作者:@skyflask
转载本文请注明出处:https://www.cnblogs.com/skyflask/articles/9757648.html
目录
Form的功能
1、原始Form
2、自定义form错误信息
3、保留上次提交的数据
4、更简洁的html标签生成
5、插件widget
6、常用插件
7、内置插件
8、form 内置字段
9、初始化操作
10、widget动态更新数据
11、内置钩子
12、序列化错误信息
13、序列化操作
14、Form总结
Form的功能
- 验证用户请求(form表单验证)
- 生成HTML标签(自动生成HTML标签)
- 保留上一次提交的数据(保留数据)
我们在设计form表单时,有许多字段需要填写,且需要判断用户填写的内容是否合法,此时,就需要对字段进行验证。试想,如果我们自己编程实现的话,需要针对用户填写的各种异常进行错误提示,此时我们需要花费大量精力去应付各种可能出现的错误,然而,Django的form为我们实现了快捷的方式,它相当于已经编写好了一个模板,只需要我们在模板的基础上进行定制。
Django中的Form表单模板是一个类,创建如下:
1、原始Form
views.py文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from django import forms # Create your views here. class FM(forms.Form): # 只关心处理自己定义的form表单数据,恶意攻击定义的数据不处理 user = forms.CharField() pwd = forms.CharField() # 这里的变量名必须和html form里的name保持一致 email = forms.EmailField() def fm(request): if request.method = = "GET" : return render(request, "fm.html" ) elif request.method = = "POST" : # 获取用户所有数据,每条数据请求的验证 # 成功 --> 获取所有的正确信息;失败 --> 显示错误信息 obj = FM(request.POST) r1 = obj.is_valid() if r1: # 返回的正确信息 print (obj.cleaned_data) else : # 返回的错误信息 print (obj.errors) print (obj.errors.as_json()) return HttpResponse( 'fm' ) |
fm.html文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!DOCTYPE html> <html lang = "en" > <head> <meta charset = "UTF-8" > <title>Title< / title> < / head> <body> <form action = "/fm/" method = "POST" > { % csrf_token % } < input type = "text" name = "user" > < input type = "text" name = "pwd" > < input type = "text" name = "email" > < input type = "submit" value = "提交" / > < / form> < / body> < / html> |
提交表单
错误输出
原始错误和json类型的错误
问题??
我们可以从上面看到错误信息,它是最简单的也是最基本的错误信息提示:为空的时候,提示字段需要填写!
此时有一个问题:我们是否可以自己定制错误信息呢?当然可以!Django的Form为我们量身定制了,而且非常简单。
2、自定义form错误信息
修改views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from django import forms class FM(forms.Form): # 只关心处理自己定义的form表单数据,恶意攻击定义的数据不处理 user = forms.CharField(error_messages = { 'required' : '用户名不能为空' }) pwd = forms.CharField( max_length = 12 , min_length = 6 , error_messages = { 'required' : '密码不能为空' , 'min_length' : '密码长度不能小于6' , 'max_length' : '密码长度不能大于12' } ) email = forms.EmailField(error_messages = { 'required' : '用户名不能为空' , 'invalid' : '邮箱格式错误' }) def fm(request): if request.method = = "GET" : return render(request, "fm.html" ) elif request.method = = "POST" : obj = FM(request.POST) r1 = obj.is_valid() if r1: # 返回的正确信息 print (obj.cleaned_data) else : # 返回的错误信息 # ErrorDict # print(obj.errors['user'][0]) # print(obj.errors.as_json()) return render(request, 'fm.html' ,{ 'obj' :obj}) return render(request, 'fm.html' ) |
修改前端html文件
1 2 3 4 5 6 7 | <form action = "/fm/" method = "POST" > { % csrf_token % } <p>< input type = "text" name = "user" > {{ obj.errors.user. 0 }}< / p> <p>< input type = "text" name = "pwd" > {{ obj.errors.pwd. 0 }}< / p> <p>< input type = "text" name = "email" > {{ obj.errors.email. 0 }}< / p> < input type = "submit" value = "提交" / > < / form> |
错误提示
问题??
此时,都有对应的错误提示了,但是有一个比较严重的问题,就是上一次提交的内容一旦提交后,就消失了!
怎么解决?
3、保留上次提交的数据
修改fm.html文件
1 2 3 4 5 6 7 | <form action = "/fm/" method = "POST" > { % csrf_token % } <p>{{ obj.user }} {{ obj.errors.user. 0 }}< / p> <p>{{ obj.pwd }} {{ obj.errors.pwd. 0 }}< / p> <p>{{ obj.email }} {{ obj.errors.email. 0 }}< / p> < input type = "submit" value = "提交" / > < / form> |
views.py文件修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def fm(request): if request.method = = "GET" : obj = FM() return render(request, "fm.html" ,{ 'obj' :obj}) elif request.method = = "POST" : obj = FM(request.POST) r1 = obj.is_valid() if r1: # 返回的正确信息 print (obj.cleaned_data) else : # 返回的错误信息 # ErrorDict # print(obj.errors['user'][0]) # print(obj.errors.as_json()) return render(request, 'fm.html' ,{ 'obj' :obj}) return HttpResponse( '提交成功!' ) |
提交成功后:
4、更简洁的html标签生成
- obj.as_p
- obj.as_ul
- obj.as_table
注意,字段的lable可以定制:通过label参数
1 | user = forms.CharField(error_messages = { 'required' : '用户名不能为空' },label = '用户名' ) |
fm.html文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!DOCTYPE html> <html lang = "en" > <head> <meta charset = "UTF-8" > <title>Title< / title> < / head> <body> <form action = "/fm/" method = "POST" > { % csrf_token % } {{ obj.as_p }} < input type = "submit" value = "提交" / > < / form> < / body> < / html> |
效果如下:
5、插件widget
form类里面的字段,只有一个功能,就是验证客户端发过来的数据。生成html的功能做不了。
但是怎么生成的html标签呢,在charfield里面有个插件,插件生成的。在其源码里做了html字符串的拼接返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from django import forms from django.forms import widgets # 插件在这里面 class FM(forms.Form): # 字段本身只做验证 user = forms.CharField( # 修改html标签,并指定样式############## error_messages = { 'required' : '用户名不能为空' }, widget = widgets.Textarea(attrs = { 'class' : 'c1' }), # 页面再看就是textarea了 label = "用户名" ) pwd = forms.CharField( max_length = 12 , min_length = 6 , error_messages = { 'required' : '密码不能为空' , 'min_length' : '密码长度不能小于6' , 'max_length' : '密码长度不能大于12' }, widget = widgets.PasswordInput # 密码密文显示,如果自定义样式也可加上(attrs……) ) email = forms.EmailField(error_messages = { 'required' : '用户名不能为空' , 'invalid' : '邮箱格式错误' }) |
字段都在from django.forms import fields
里面,所以上面的forms可以改用fields
email = fields.EmailField()
前端<p>{{ obj.user.label }}{{ obj.user }} {{ obj.errors.user.0 }}</p>
插件里面input、checkbox、select、redio等全部都有。
6、常用插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # 单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 # ) |
7、内置插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
8、form 内置字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 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类型 ... |
9、初始化操作
在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。
1 2 3 4 5 6 7 8 9 10 11 | def fm(request): if request.method = = "GET" : dic = { "user" : 'r1' , "pwd" : '123456' , "email" : 'aera@11.com' , "city" : 1 , "city2" :[ 1 , 2 ], } obj = FM(initial = dic) # 初始化 return render(request, "fm.html" ,{ 'obj' :obj}) |
10、widget动态更新数据
models.py文件
1 2 3 4 5 6 7 8 9 10 11 12 | # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models # Create your models here. class UserType(models.Model): caption = models.CharField(max_length = 32 ) def __str__( self ): return self .caption |
forms.py文件
1 2 3 4 5 6 7 8 9 10 11 12 | #coding:utf-8 from django import forms from django.forms import fields from app01 import models from django.core.exceptions import ValidationError class UserInfoForm(forms.Form): username = fields.CharField(max_length = 32 ) email = fields.EmailField(max_length = 32 ) user_type = fields.ChoiceField( choices = models.UserType.objects.values_list( 'id' , 'caption' ) ) |
views.py文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def index(request): if request.method = = 'GET' : obj = UserInfoForm() new_obj = models.User.objects. all () return render(request, 'index.html' ,{ 'obj' :obj, 'new_obj' :new_obj}) elif request.method = = 'POST' : obj = UserInfoForm(request.POST) if obj.is_valid(): rt_dic = obj.cleaned_data username = rt_dic.get( 'username' ) email = rt_dic.get( 'email' ) user_type_id = rt_dic.get( 'user_type' ) ut = models.UserType.objects. filter ( id = user_type_id).first() models.User.objects.create(username = username,email = email,user_type = ut) return render(request, 'index.html' ,{ 'obj' :obj}) |
问题??
上面有个问题,就是数据库添加数据后,django需要重启网页才能看到新加的数据。为什么会这样呢?
forms里面,定义的类,类里的username、email、user_type都是静态字段(类变量),这些都是属于类的。
在__init__里面写的属于对象。
而启动Django的时候,类变量一次性都加在到内存了。
上面views.py里的obj = UserInfoForm()生成了一个对象,会执行类里的__init__方法,会把类里的字段封装到obj.fields里面(里面有username、email、user_type三个字段),所以:
我们可以考虑在form加载的时候进行数据初始化,也就是在forms.py的__init__()里面做文章:
1 2 3 4 5 | # 下面的操作是让数据在网页上实时更新:每次刷新时,必先执行父类的初始化函数,再设定下拉列表框选项。 def __init__( self , * args, * * kwargs): super (UserInfoForm, self ).__init__( * args, * * kwargs) self .fields[ 'user_type' ].choices = models.UserType.objects.values_list( 'id' , 'caption' ) |
通过widgets还有另外两种方法进行更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #coding:utf-8 from django import forms from django.forms import fields,widgets,ModelChoiceField from app01 import models from django.core.exceptions import ValidationError class UserInfoForm(forms.Form): username = fields.CharField(max_length = 32 ) email = fields.EmailField(max_length = 32 ) #和user_type2类似,只是参数改变了方式 user_type = fields.ChoiceField( choices = [], widget = widgets.Select ) user_type2 = fields.ChoiceField( widget = widgets.Select(choices = []) ) #ModelChoiceField参数 """ ModelChoiceField(ChoiceField) django.forms.models.ModelChoiceField queryset, # 查询数据库中的数据 empty_label="---------", # 默认空显示内容 to_field_name=None, # HTML中value的值对应的字段(html源码中value不同) limit_choices_to=None # ModelForm中对queryset二次筛选 """ user_type3 = ModelChoiceField( queryset = models.UserType.objects. all () ) # 下面的操作是让数据在网页上实时更新:每次刷新时,必先执行父类的初始化函数,再设定下拉列表框选项。 def __init__( self , * args, * * kwargs): super (UserInfoForm, self ).__init__( * args, * * kwargs) self .fields[ 'user_type' ].choices = models.UserType.objects.values_list( 'id' , 'caption' ) self .fields[ 'user_type2' ].widget.choices = models.UserType.objects.values_list( 'id' , 'caption' ) |
实现效果如下:
当然,在models.py文件里面还需要新增__str__()方法:
1 2 3 4 5 | class UserType(models.Model): caption = models.CharField(max_length = 32 ) def __str__( self ): return self .caption |
11、内置钩子
初始化操作
Form里面加一个字典数据,生成显示默认值
1 2 3 4 | def index(request): from cmdb.forms import UserInfoForm obj = UserInfoForm({ 'username' : 'xq' , 'email' : 'xq@qq.com' , 'user_type' : '1' }) # 默认值 return render(request, 'index.html' , { 'obj' :obj}) |
效果如下:
数据验证
obj.is_valid()#做简单的数据验证,查看源码可以知道,这个方法有2个功能:一个是判断是否有字段为空,一个是判断是否有错误信息。
1 2 3 4 5 6 7 8 | def is_valid( self ): """ Returns True if the form has no errors. Otherwise, False. If errors are being ignored, returns False. """ return self .is_bound and not self .errors self .is_bound = data is not None or files is not None |
问题??虽然我们可以通过is_valid()方法进行简单的验证,但是错误提示和错误信息我们都无法定制。
怎么解决呢?form提供了接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #清洗单个字段 def clean_username(self): # value = self .cleaned_data[ 'username' ] if value = = 'root' : return value else : raise ValidationError( '你不是超级用户...' ) #清洗钩子,可以自定义 def clean( self ): username = self .cleaned_data.get( 'username' ) email = self .cleaned_data.get( 'email' ) if models.User.objects. filter (username = username, email = email).count() = = 1 : raise ValidationError( '用户名和邮箱联合唯一索引重复!!!' ) return self .cleaned_data #清洗钩子,可以自定义 def _post_clean( self ): print 'aaa %s' % self .cleaned_data username = self .cleaned_data[ 'username' ] email = self .cleaned_data[ 'email' ] if models.User.objects. filter (username = username,email = email).count() = = 1 : self .add_error( "__all__" , ValidationError( '用户名和邮箱联合唯一索引重复!!!' )) |
在form验证里面的顺序:
is_valid()===》self.errors()和self.is_bound()===>self.full_clean()===》self._clean_fields()===>self._clean_form()===》self._post_clean()
form验证,
- 先第一个字段正则表达式判断,执行字段钩子函数clean_fields();
- 第二个字段正则,第二个的钩子;
- 所有字段完成后,执行clean()钩子;
- clean执行完后,执行
_post_clean()
钩子
12、序列化错误信息
不管提交数据是浏览器提交、还是curl方式,还是ajax提交,只要是request.POST
都可以做验证。
res['error'] = obj.errors.as_json() # 转为json格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <script src = "/static/jquery-1.12.4.js" >< / script> <script> / / 页面框架加载完自动执行 $( '#submit' ).click(function(){ $.ajax({ url: '/login.html' , type : 'POST' , data:$( '#fm' ).serialize(), success:function(arg){ console.log(arg); arg = JSON.parse(arg); / / 转为字典 console.log(arg); }, error: function(){ } }) }) < / script> |
上面的方式可以实现,只是前端需要反解两次,不太好,下面优化一下。
- as_json : 生成json格式
- as_data : 生成dict数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | from django import forms from django.forms import widgets, fields class LoginForm(forms.Form): username = fields.CharField() password = fields.CharField( max_length = 64 , min_length = 12 ) # 序列化,转换为指定数据类型 import json from django.core.exceptions import ValidationError class JsonCustomEncoder(json.JSONEncoder): def default( self , field): if isinstance (field, ValidationError): return { 'code' :field.code, 'messages' : field.messages} else : return json.JSONEncoder.default( self , field) def login(request): res = { 'status' : True , 'error' : None , 'data' : None } if request.method = = "GET" : return render(request, "login.html" ) elif request.method = = "POST" : obj = LoginForm(request.POST) if obj.is_valid(): print (obj.cleand_data) else : # print(obj.errors, type(obj.errors)) # res['error'] = obj.errors.as_json() # 转为json格式 print ( type (obj.errors.as_data())) for k,v in obj.errors.as_data().items(): print (k,v) # 这里v是ValidationError类型,不能序列化 res[ 'error' ] = obj.errors.as_data() result = json.dumps(res, cls = JsonCustomEncoder) return HttpResponse(json.dumps(result)) |
13、序列化操作
Json.dumps
用来做序列化,但是只能序列化一些简单的基本数据类型。对于无法序列化的数据类型,只能自定制了。
ErrorDict自定义JSONEncoder
由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default( self , field): if isinstance (field, datetime): return o.strftime( '%Y-%m-%d %H:%M:%S' ) elif isinstance (field, date): return o.strftime( '%Y-%m-%d' ) # 转成字符串类型 else : return json.JSONEncoder.default( self , field) v = { 'k' : '123' , "k1" :datetime.datetime.now()} ds = json.dumps(v, cls = JsonCustomEncoder) |
QuerySet 第一种序列化方式
上面自己写实现也可以,不过Django提供了方法做序列化
1 2 3 4 | from django.core import serializers v = models.tb.objects. all () data = serializers.serialize( "json" , v) |
QuerySet 第二种序列化方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default( self , field): if isinstance (field, datetime): return field.strftime( '%Y-%m-%d %H:%M:%S' ) elif isinstance (field, date): return field.strftime( '%Y-%m-%d' ) else : return json.JSONEncoder.default( self , field) v = models.tb.objects.values( 'id' , 'name' , 'ctime' ) v = list (v) # 把(类似列表的queryset类型)转换为列表 v = json.dumps(v, cls = JsonCustomEncoder) # 这里cls只对ctime操作。 # 如果没有ctime这个类型,只写上边的三句就可以实现 |
14、Form总结
我们在程序中使用Form表单非常多,Django中的Form类除了具备form表单功能外,它最强大的是它的数据验证功能,让编程人员省去了很多事情,而且它的数据验证非常灵活。
a、Form数据字段验证过程:
首先,我们可以使用is_valid()方法,对表单字段进行简单数据验证(是否为空或有errors),其中errors会调用full_clean(),【空字段或简单错误】
紧接着,full_clean()函数里面会有每个字段的正则,clean_field()然后会调用_clean_form(),它里面会有clean()钩子,【清洗字段、清洗整个表单,可灵活自定义】
最后会调用_post_clean()钩子。【清洗提交数据,可灵活自定义】
b、Form数据返回值:
is_valid()进行数据验证,然后通过cleaned_data获取数据字典,errors获取错误字典。
c、Form数据实时更新:
在form类初始化时,把对象进行实时拉取最新数据,保证数据为最新。
1 2 3 | super (UserInfoForm, self ).__init__( * args, * * kwargs) self .fields[ 'user_type' ].choices = models.UserType.objects.values_list( 'id' , 'caption' ) self .fields[ 'user_type2' ].widget.choices = models.UserType.objects.values_list( 'id' , 'caption' ) |
d、序列化数据
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」