PythonDjango的表单form组件
form组件使用方法
form组件主要有三个用途:生成页面可用的HTML标签对用户提交的数据进行校验保留上次输入内容
使用步骤:在应用文件夹下创建一个文件,名字随意,比如myforms。py。创建form类,继承自django。forms。Form:fromdjangoimportformsclassLoginForm(forms。Form):usernamerequest。POST。get(username)ifinusername:raise{username:xxxx,password:}usernameforms。CharField(label用户名:,requiredTrue,不能为空,默认可不写maxlength7,长度不能超过7个字符minlength2,最短不能低于2个字符initial张三,初始值widgetforms。TextInput(attrs{class:c1,placeholder:请输入用户名}),errormessages{required:不能为空,maxlength:太长了,难受!,minlength:太短了,更难受!,},)passwordforms。CharField(requiredTrue,label密码:,widgetforms。PasswordInput(attrs{class:c1,placeholder:请输入密码},rendervalueTrue),rendervalueTrue让密码输入的数据保留)sexforms。ChoiceField(choices〔(1,男),(2,女)〕,widgetforms。RadioSelect(attrs{xx:none}),)
3。在views中实例化这个类对象,并交给前端html页面:deflogin(request):ifrequest。methodGET:formobjLoginForm()returnrender(request,login。html,{formobj:formobj})else:formobjLoginForm(request。POST)准备校验,也就是检查不符合格式的部分,并且保存到列表中,写成伪代码为:formobjusername:alexxxxxxformobj。username。errors。append(太长了!!)username:alexxxxxxformobj。username。errors。append(包含了!feifazifu)passwordformobj。password。errors。append(太长了!!)print(status)returnrender(request,login。html,{formobj:formobj})
4。进行数据格式校验:formobjLoginForm(request。POST)statusformobj。isvalid()开始校验,第三步的伪代码Django已经封装好,直接使用即可print(status)returnrender(request,login。html,{formobj:formobj}
5。在前端页面中可以写成这样使用表单信息:常用字段CharField普通文本
不要被名字骗到,后面的密码输入,还有其他各种输入框,基本都是在这个CharField的基础上通过插件来搞的。
不过CharFIield最原本的用途,还是用来输入普通文本:usernameforms。CharField(也可写成forms。field。CharField而这等价,后面的字段也一样label用户名:,initial张三设置默认值requiredTrue,不能为空,默认可不写maxlength7,长度不能超过7个字符minlength2,最短不能低于2个字符initial张三,初始值widgetforms。TextInput(attrs{class:c1,placeholder:请输入用户名}),errormessages{required:不能为空,maxlength:太长了,难受!,minlength:太短了,更难受!,},密码输入
form中是没有密码输入的字段的,需要配合CharField来写,在插件中设置为密码输入。密码字段和其他字段不一样,默认在前端输入数据错误的时候,点击提交之后,不保存的原来数据。可以通过设置rendervalueTrue让这个字段在前端保留用户输入的数据:passwordforms。CharField(requiredTrue,minlength6,label密码:,widgetforms。PasswordInput(attrs{class:c1,placeholder:请输入密码},rendervalueTrue),rendervalueTrue让密码输入的数据保留)radioSelect单选
注意这个不是CharField,而是ChoiceField:sexforms。ChoiceField(choices〔(1,男),(2,女)〕,widgetforms。RadioSelect(attrs{xx:none}),)单选Select下拉框
注意,单选框用的是ChoiceField,并且里面的插件是Select,不然验证的时候会报Selectavalidchoice的错误。hobbyforms。ChoiceField(choices((1,篮球),(2,足球),(3,双色球),),label爱好,initial3,widgetforms。widgets。Select())多选Select下拉框
多选框的时候用MultipleChoiceField,并且里面的插件用的是SelectMultiple,不然验证的时候会报错。hobbyforms。MultipleChoiceField(choices((1,篮球),(2,足球),(3,双色球),),label爱好,initial〔1,3〕,widgetforms。widgets。SelectMultiple())单选checkboxkeepforms。ChoiceField(label是否记住密码,initialchecked,widgetforms。widgets。CheckboxInput())多选checkboxhobbyforms。MultipleChoiceField(choices((1,篮球),(2,足球),(3,双色球),),label爱好,initial〔1,3〕,widgetforms。widgets。CheckboxSelectMultiple())时间输入date
必须指定type,不然不能渲染成选择时间的input框:dateforms。DateField(widgetforms。widgets。TextInput(attrs{type:date}))从数据库中动态载入choice字段
在使用选择标签时,需要choices的选项配置往往要从数据库中获取。但是如果按照往常一样静态字段,写死了,获取的值无法实时更新。这时就需要重写构造方法从而实现choice实时更新。
方式一,从数据库中查找,将结果作为choices的值传入:fromdjango。formsimportFormfromdjango。formsimportwidgetsfromdjango。formsimportfieldsclassMyForm(Form):userfields。ChoiceField(choices((1,上海),(2,北京),),initial2,widgetwidgets。Select)definit(self,args,kwargs):super(MyForm,self)。init(args,kwargs)注意重写init方法的时候,args和kwargs一定要给人家写上,不然会出问题,并且验证总是不能通过,还不显示报错信息self。fields〔user〕。choices((1,上海),(2,北京),)或self。fields〔user〕。choicesmodels。Classes。objects。all()。valueslist(id,caption)
方法二,将选项作为模型对象,整个传入:
如果用这种方式,别忘了model模型表中,要写上NNEWType的str方法,不然选择框里面将会是一个个的object对象。fromdjangoimportformsfromdjango。formsimportfieldsclassFInfo(forms。Form):authorsforms。ModelMultipleChoiceField(querysetmodels。NNewType。objects。all())多选或者下面这种方式,通过forms里面的models中提供的方法也是一样的。authorsforms。models。ModelMultipleChoiceField(querysetmodels。NNewType。objects。all())多选authorsforms。models。ModelChoiceField(querysetmodels。NNewType。objects。all())单选或者authorsforms。ModelChoiceField(querysetmodels。Publisth。objects。all(),widgetforms。Select())单选authorsforms。ModelMultipleChoiceField(querysetmodels。Author。objects。all(),widgetforms。Select(attrs{class:formcontrol}))form所有的内置字段
注:有些字段因不常用,其属性以。。。表示暂不介绍。FieldrequiredTrue,是否允许为空widgetNone,HTML插件labelNone,用于生成Label标签或显示内容initialNone,初始值helptext,帮助信息(在标签旁边显示)errormessagesNone,错误信息{required:不能为空,invalid:格式错误}validators〔〕,自定义验证规则localizeFalse,是否支持本地化disabledFalse,是否可以编辑labelsuffixNoneLabel内容后缀CharField(Field)maxlengthNone,最大长度minlengthNone,最小长度stripTrue是否移除用户输入空白IntegerField(Field)maxvalueNone,最大值minvalueNone,最小值FloatField(IntegerField)。。。DecimalField(IntegerField)maxvalueNone,最大值minvalueNone,最小值maxdigitsNone,总长度decimalplacesNone,小数位长度BaseTemporalField(Field)inputformatsNone时间格式化DateField(BaseTemporalField)格式:20150901TimeField(BaseTemporalField)格式:11:12DateTimeField(BaseTemporalField)格式:2015090111:12DurationField(Field)时间间隔:dH:M:S。f。。。RegexField(CharField)regex,自定制正则表达式maxlengthNone,最大长度minlengthNone,最小长度errormessageNone,忽略,错误信息使用errormessages{invalid:。。。}EmailField(CharField)。。。FileField(Field)allowemptyfileFalse是否允许空文件ImageField(FileField)。。。注:需要PIL模块,pip3installPillow以上两个字典使用时,需要注意两点:form表单中enctypemultipartformdataview函数中objMyForm(request。POST,request。FILES)URLField(Field)。。。BooleanField(Field)。。。NullBooleanField(BooleanField)。。。ChoiceField(Field)。。。choices(),选项,如:choices((0,上海),(1,北京),)requiredTrue,是否必填widgetNone,插件,默认select插件labelNone,Label内容initialNone,初始值helptext,帮助提示ModelChoiceField(ChoiceField)。。。django。forms。models。ModelChoiceFieldqueryset,查询数据库中的数据emptylabel,默认空显示内容tofieldnameNone,HTML中value的值对应的字段limitchoicestoNoneModelForm中对queryset二次筛选ModelMultipleChoiceField(ModelChoiceField)。。。django。forms。models。ModelMultipleChoiceFieldTypedChoiceField(ChoiceField)coercelambdaval:val对选中的值进行一次转换emptyvalue空值的默认值MultipleChoiceField(ChoiceField)。。。TypedMultipleChoiceField(MultipleChoiceField)coercelambdaval:val对选中的每一个值进行一次转换emptyvalue空值的默认值ComboField(Field)fields()使用多个验证,如下:即验证最大长度20,又验证邮箱格式fields。ComboField(fields〔fields。CharField(maxlength20),fields。EmailField(),〕)MultiValueField(Field)PS:抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用SplitDateTimeField(MultiValueField)inputdateformatsNone,格式列表:〔Ymd,mdY,mdy〕inputtimeformatsNone格式列表:〔H:M:S,H:M:S。f,H:M〕FilePathField(ChoiceField)文件选项,目录下文件显示在页面中path,文件夹路径matchNone,正则匹配recursiveFalse,递归下面的文件夹allowfilesTrue,允许文件allowfoldersFalse,允许文件夹requiredTrue,widgetNone,labelNone,initialNone,helptext,GenericIPAddressFieldprotocolboth,both,ipv4,ipv6支持的IP格式unpackipv4False解析ipv4地址,如果是::ffff:192。0。2。1时候,可解析为192。0。2。1,PS:protocol必须为both才能启用SlugField(CharField)数字,字母,下划线,减号(连字符)。。。UUIDField(CharField)uuid类型数据校验
我们可以字段中的参数对用户输入的数据进行初步校验。但有些时候,我们需要更复杂的校验模式,就需要自定义校验规则。
数据校验流程:循环所有的自己form类中的所有字段进行字段中charfield()类实例化时传入的校验规则(包括validators的规则)进行校验,然后进行该字段局部钩子的校验。然后进行下一次循环,也就是校验下一个字段。完成之后,self。cleaneddata里面有了每个字段的数据执行全局钩子validators
通过创建的校验函数,在声明form字段时使用validators属性引入。其基本用法为:importrefromdjangoimportformsfromdjango。core。exceptionsimportValidationErrorfromdjango。core。validatorsimportRegexValidator正则校验器这个函数的作用等价于:RegexValidator(r(13〔09〕15〔012356789〕)〔09〕{8}39;,手机号码格式错误)defmobilevalidate(value):mobilerere。compile(r(13〔09〕15〔012356789〕)〔09〕{8}39;)ifnotmobilere。match(value):raiseValidationError(手机号码格式错误)classLoginForm(forms。Form):野蛮校验法:usernamerequest。POST。get(username)ifinusername:raise{username:xxxx,password:}phoneforms。CharField(label用户名:,requiredTrue,不能为空minlength11,最短不能低于11个字符maxlength11,应用validator,注意是个列表validators〔mobilevalidate,RegexValidator(r。。,请输入正确手机号)〕,widgetforms。TextInput(attrs{class:c1,placeholder:请输入手机号}),errormessages{required:不能为空,maxlength:太长了!,minlength:太短了!,},)局部钩子
局部钩子用来校验特定的某个字段,之前的校验规则还在,给你提供了一个添加一些校验功能的钩子。其基本用法为:importrefromdjangoimportformsfromdjango。core。exceptionsimportValidationErrorfromdjango。core。validatorsimportRegexValidatorclassLoginForm(forms。Form):usernameforms。CharField(label用户名:,requiredTrue,minlength2,widgetforms。TextInput(attrs{class:c1,placeholder:请输入用户名}),errormessages{required:不能为空,maxlength:太长了,难受!,minlength:太短了,更难受!,},)defcleanusername(self):valueself。cleaneddata。get(username)print(value,type(value))if666invalue:不能含有666raiseValidationError(光喊6是没用的!)else:returnvalue全局钩子
如果我们要校验两个或多个有关联的数据,就需要用到全局钩子,待其他校验操作完成后,进行数据校验。
我们在Fom类中定义clean()方法,就能够实现对字段进行全局校验。字段全部验证完,局部钩子也全部执行完之后,执行这个全局钩子校验:fromdjango。shortcutsimportrenderimportrefromdjango。core。exceptionsimportValidationErrorfromdjango。core。validatorsimportRegexValidatorfromdjangoimportformsdefmobilevalidate(value):mobilerere。compile(r(13〔09〕15〔012356789〕)〔09〕{8}39;)ifnotmobilere。match(value):raiseValidationError(手机号码格式错误)classLoginForm(forms。Form):passwordforms。CharField(requiredTrue,label密码:,widgetforms。PasswordInput(attrs{class:c1,placeholder:请输入密码},rendervalueTrue),rendervalueTrue让密码输入的数据保留)confirmpasswordforms。CharField(requiredTrue,label确认密码:,widgetforms。PasswordInput(attrs{class:c1,placeholder:请输入密码},rendervalueTrue),rendervalueTrue让密码输入的数据保留)全局钩子,用来比较密码与验证秘法是否一致defclean(self):p1self。cleaneddata。get(password)p2self。cleaneddata。get(confirmpassword)ifp1p2:returnself。cleaneddataelse:raiseValidationError(两次密码不一致!!!你是熊华吗!!!)全局错误,cleaneddata数据不变self。adderror(confirmpassword,两次密码不一致,你是彭于晏吗!!!!)指定字段错误,cleaneddata中不再有confirmpasswordcleaneddata和errors的简单讨论
经过验证,用户输入的数据将会分成两部分:合乎规则的和不合规则的。每次校验后,合乎规则的数据将会放在cleaneddata中,不合规则的数据会放在errors中。下一步的校验,将只校验cleaneddata中的数据。
cleaneddata是完成前一步校验后的合格数据,是一个字典,键是每一个字段名,值是合格的数据,追根溯源是用户输入进来的。操作cleaneddata的方式也和操作字典相同(废话,人家本身就是字典)。
cleaneddata是类属性,通过self。cleaneddata查找和使用。
errors校验不合格的数据会放在errors里面,储存形式为字典:{字段名:〔报错信息〕,all:〔全部报错信息〕}
字段的属性规则和局部钩子产生的错误,通过捕获ValidationError获取。捕获到这个错误后,会将出错的字段从cleaneddata字典中移除,将其存放到errors字典中。用户输入的数据因为不合规范,所以不会保存,取而代之的是设置的报错信息。
如果是全局钩子报错,也是抛出的ValidationError。如果没有进行其他操作,不会删除cleaneddata中的字段,而是会在errors字典中创建一个all关键字,将全局钩子的错误信息放到其中。在抛出异常之前,我们可以调用self。adderror方法,将错误指定给某个字段。调用这个方法会将该字段从cleaneddata中移除,并添加到errors字典中,值将会是报错信息。当然,如果后面还有抛出ValidationError的话,还是会在errors字典中加上all关键字放入全局报错信息的。所以在全局钩子中,两种方式没有必要同时使用。数据校验综合案例fromdjango。shortcutsimportrenderimportrefromdjango。core。exceptionsimportValidationErrorfromdjango。core。validatorsimportRegexValidatorfromdjangoimportformsdefmobilevalidate(value):mobilerere。compile(r(13〔09〕15〔012356789〕)〔09〕{8}39;)ifnotmobilere。match(value):raiseValidationError(手机号码格式错误)classLoginForm(forms。Form):usernameforms。CharField(label用户名:,requiredTrue,minlength2,validators〔mobilevalidate,〕,widgetforms。TextInput(attrs{class:c1,placeholder:请输入用户名}),errormessages{required:不能为空,maxlength:太长了,难受!,minlength:太短了,更难受!,},)passwordforms。CharField(requiredTrue,label密码:,widgetforms。PasswordInput(attrs{class:c1,placeholder:请输入密码},rendervalueTrue),rendervalueTrue让密码输入的数据保留)confirmpasswordforms。CharField(requiredTrue,label确认密码:,widgetforms。PasswordInput(attrs{class:c1,placeholder:请输入密码},rendervalueTrue),)局部钩子defcleanusername(self):valueself。cleaneddata。get(username)print(value,type(value))if666invalue:不能含有666raiseValidationError(光喊6是没用的!)else:returnvalue全局钩子defclean(self):p1self。cleaneddata。get(password)p2self。cleaneddata。get(confirmpassword)ifp1p2:returnself。cleaneddataelse:raiseValidationError(两次密码不一致!!!你是熊华吗!!!)self。adderror(confirmpassword,两次密码不一致,你是彭于晏吗!!!!)HTML写法formobj
直接在模板渲染语法中写formobj可以直接以表格的形式生成所有的表单标签,但因为格式不易操作,所以几乎不这么直接用:{{formobj}}asp
自动生成所有带label标签的input标签,也跟上面一样,不常用。用法:{{formobj。asp}}字段名
生成字段名对应的input标签:{{formobj。字段名}}label
生成字段名标签,也就是字段中的label属性对应的值,若不写label属性,默认是字段名:{{formobj。字段名。label}}idforlabel
生成的input标签的id,用来给label分配input标签:labelfor{{formobj。字段名。idforlabel}}{{formobj。字段名。label}}labelerrors
errors是生成错误的集合,本质上是字典,但是重写了str方法,在页面上会把所有错误以无序列表的形式显现,但我们一般不会把错误这么打印出来,我们一般会针对每个字段打印:{{formobj。errors}}!输出所有错误出来{{formobj。字段名。errors}}!输出指定字段的错误,是个列表{{formobj。字段名。errors。0}}!实际上我们常这样,只拿第一个错误,没必要全拿出来综合使用labelfor{{formobj。username。idforlabel}}{{formobj。username。label}}label{{formobj。username}}span{{formobj。username。errors。0}}span批量增加样式(比如Bootstrap样式)classLoginForm(forms。Form):usernameforms。CharField(minlength8,label用户名,initial张三,errormessages{required:不能为空,invalid:格式错误,minlength:用户名最短8位}definit(self,args,kwargs):super(LoginForm,self)。init(args,kwargs)forfieldiniter(self。fields):self。fields〔field〕。widget。attrs。update({class:formcontrol,Bootstrap表单样式})
中秋节,这6道菜端上桌,福气自然进家门,家宴吉祥菜要收好中秋佳节,无论工作多忙,有钱没钱,按照中国的传统习俗,都是要和家人团圆的,全家聚在一起吃月饼赏明月话家常,享受阖家团圆的幸福时刻。良辰美景,一顿喜庆又丰盛的家宴是不能少的,和往常的
零点自然双减全套解决方案玩泥巴的好处分享带娃日记,留住美好时光,培养健康人格!零点自然教育研习社泥是大地的元素,是自然的产物,也孕育了人类丰富的文化。玩泥巴是孩子的天性,可是大部分家长都不太愿意让孩子去玩泥巴,担心他
DNF天界已拉闸,机械战神即将到来,未来战士们准备好了嘛?在先遣服机械战神高级图已经上线,在8。11日的更新中正式服也将进入机械战神的版本,不少备战未来版本的未来战士们的刷图点已经屯好了吗?屯刷图点为什么要屯刷图点呢?因为机械战神实验室这
iG在RA伤口撒盐,三局比赛击碎RA季后赛梦想英雄联盟S12赛季,LPL夏季赛常规赛进入了最后的收官阶段,季后赛门票还剩4张。而有机会拿到这四张门票的队伍,却还有6支之多。也就是说,这最后几场比赛,对于有志于季后赛和银龙杯的战
糖尿病人少吃甜食就行?这5种不甜的食物也要限量老王今年61岁,糖尿病三年了,血糖血脂一直控制不佳,后来一问,发现有个吃零食的习惯,每天吃些花生瓜子,加起来有半斤,但是从来不吃甜食。乖乖,这个半斤花生瓜子可是比半斤甜食的热量还高
用饮料服用药物有哪些危害所见所得,都很科学人在一生中,免不了生病,生病了免不了用药,用药了免不了用水冲服,但是有人喜欢用饮料冲服,到底能不能用饮料冲服?用饮料冲服有哪些危害呢?常喝的雪碧可乐饮料一饮料能不
无糖月饼,能否放开吃?中秋佳节到了,万家团圆少不了月饼。近年来,无糖月饼成为了最新网红,它自称没有糖,不会升高血糖,是老人血糖偏高以及糖尿病友人(以下简称糖友)的福音,并以健康养生自居。随之而来的是,很
百病,皆归脾!教你健脾丸4种搭配,健脾和胃,抵御百病大家好,我去屈医生,百病皆归脾!今天给大家分享健脾丸的4种巧搭配,健脾和胃,抵御病邪。健脾丸由白术茯苓人参甘草山药山楂神曲麦芽肉豆蔻木香砂仁陈皮黄连组成,能够健脾和胃,消食止泻,除
不小心落枕了,怎么自我按摩缓解?落枕主要是由于睡枕睡眠姿势不正,或受风寒而引起的急性颈部,或牵连背部明显疼痛颈部活动受限等一组症状。落枕主要表现为颈部会相对固定在某一体位颈部疼痛,颈部活动,如左右旋转左右侧弯前屈
手有时候会抖是怎么回事?手抖的原因有很多在印象中,手抖一般都是老年人才会出现,但现在这种症状在年轻人身上很常见。大多数年轻人都选择了无视,很多时候这只是一种小问题,只要稍加注意就行了,那么手有时候会抖是怎么回事?接下来为
肠息肉是什么原因导致的?生活中需要注意哪些方面?肠息肉是比较常见的一种肠道疾病,多是在做肠镜时无意间发现。很多人比较关心自己为什么会得肠息肉,肠息肉切掉后,还会不会再长。要了解肠息肉是怎么导致的,我们首先要知道肠息肉是什么。肠息