django框架forms组件用法实例详解
本文实例讲述了django框架forms组件用法。分享给大家供大家参考,具体如下:
在django中forms组件有其强大的功能,里面集合和众多的函数和方法:下面来看一下它的源码
""" Formclasses """ from__future__importunicode_literals importcopy fromcollectionsimportOrderedDict fromdjango.core.exceptionsimportNON_FIELD_ERRORS,ValidationError #BoundFieldisimportedforbackwardscompatibilityinDjango1.9 fromdjango.forms.boundfieldimportBoundField#NOQA fromdjango.forms.fieldsimportField,FileField #pretty_nameisimportedforbackwardscompatibilityinDjango1.9 fromdjango.forms.utilsimportErrorDict,ErrorList,pretty_name#NOQA fromdjango.forms.widgetsimportMedia,MediaDefiningClass fromdjango.utilsimportsix fromdjango.utils.encodingimportforce_text,python_2_unicode_compatible fromdjango.utils.functionalimportcached_property fromdjango.utils.htmlimportconditional_escape,html_safe fromdjango.utils.safestringimportmark_safe fromdjango.utils.translationimportugettextas_ from.renderersimportget_default_renderer __all__=('BaseForm','Form') classDeclarativeFieldsMetaclass(MediaDefiningClass): """ MetaclassthatcollectsFieldsdeclaredonthebaseclasses. """ def__new__(mcs,name,bases,attrs): #Collectfieldsfromcurrentclass. current_fields=[] forkey,valueinlist(attrs.items()): ifisinstance(value,Field): current_fields.append((key,value)) attrs.pop(key) current_fields.sort(key=lambdax:x[1].creation_counter) attrs['declared_fields']=OrderedDict(current_fields) new_class=super(DeclarativeFieldsMetaclass,mcs).__new__(mcs,name,bases,attrs) #WalkthroughtheMRO. declared_fields=OrderedDict() forbaseinreversed(new_class.__mro__): #Collectfieldsfrombaseclass. ifhasattr(base,'declared_fields'): declared_fields.update(base.declared_fields) #Fieldshadowing. forattr,valueinbase.__dict__.items(): ifvalueisNoneandattrindeclared_fields: declared_fields.pop(attr) new_class.base_fields=declared_fields new_class.declared_fields=declared_fields returnnew_class @html_safe @python_2_unicode_compatible classBaseForm(object): #ThisisthemainimplementationofalltheFormlogic.Notethatthis #classisdifferentthanForm.SeethecommentsbytheFormclassformore #information.AnyimprovementstotheformAPIshouldbemadeto*this* #class,nottotheFormclass. default_renderer=None field_order=None prefix=None use_required_attribute=True def__init__(self,data=None,files=None,auto_id='id_%s',prefix=None, initial=None,error_class=ErrorList,label_suffix=None, empty_permitted=False,field_order=None,use_required_attribute=None,renderer=None): self.is_bound=dataisnotNoneorfilesisnotNone self.data=dataor{} self.files=filesor{} self.auto_id=auto_id ifprefixisnotNone: self.prefix=prefix self.initial=initialor{} self.error_class=error_class #Translators:Thisisthedefaultsuffixaddedtoformfieldlabels self.label_suffix=label_suffixiflabel_suffixisnotNoneelse_(':') self.empty_permitted=empty_permitted self._errors=None#Storestheerrorsafterclean()hasbeencalled. #Thebase_fieldsclassattributeisthe*class-wide*definitionof #fields.Becauseaparticular*instance*oftheclassmightwantto #alterself.fields,wecreateself.fieldsherebycopyingbase_fields. #Instancesshouldalwaysmodifyself.fields;theyshouldnotmodify #self.base_fields. self.fields=copy.deepcopy(self.base_fields) self._bound_fields_cache={} self.order_fields(self.field_orderiffield_orderisNoneelsefield_order) ifuse_required_attributeisnotNone: self.use_required_attribute=use_required_attribute #Initializeformrenderer.Useaglobaldefaultifnotspecified #eitherasanargumentorasself.default_renderer. ifrendererisNone: ifself.default_rendererisNone: renderer=get_default_renderer() else: renderer=self.default_renderer ifisinstance(self.default_renderer,type): renderer=renderer() self.renderer=renderer deforder_fields(self,field_order): """ Rearrangesthefieldsaccordingtofield_order. field_orderisalistoffieldnamesspecifyingtheorder.Fieldsnot includedinthelistareappendedinthedefaultorderforbackward compatibilitywithsubclassesnotoverridingfield_order.Iffield_order isNone,allfieldsarekeptintheorderdefinedintheclass. Unknownfieldsinfield_orderareignoredtoallowdisablingfieldsin formsubclasseswithoutredefiningordering. """ iffield_orderisNone: return fields=OrderedDict() forkeyinfield_order: try: fields[key]=self.fields.pop(key) exceptKeyError:#ignoreunknownfields pass fields.update(self.fields)#addremainingfieldsinoriginalorder self.fields=fields def__str__(self): returnself.as_table() def__repr__(self): ifself._errorsisNone: is_valid="Unknown" else: is_valid=self.is_boundandnotbool(self._errors) return'<%(cls)sbound=%(bound)s,valid=%(valid)s,fields=(%(fields)s)>'%{ 'cls':self.__class__.__name__, 'bound':self.is_bound, 'valid':is_valid, 'fields':';'.join(self.fields), } def__iter__(self): fornameinself.fields: yieldself[name] def__getitem__(self,name): "ReturnsaBoundFieldwiththegivenname." try: field=self.fields[name] exceptKeyError: raiseKeyError( "Key'%s'notfoundin'%s'.Choicesare:%s."%( name, self.__class__.__name__, ','.join(sorted(fforfinself.fields)), ) ) ifnamenotinself._bound_fields_cache: self._bound_fields_cache[name]=field.get_bound_field(self,name) returnself._bound_fields_cache[name] @property deferrors(self): "ReturnsanErrorDictforthedataprovidedfortheform" ifself._errorsisNone: self.full_clean() returnself._errors defis_valid(self): """ ReturnsTrueiftheformhasnoerrors.Otherwise,False.Iferrorsare beingignored,returnsFalse. """ returnself.is_boundandnotself.errors defadd_prefix(self,field_name): """ Returnsthefieldnamewithaprefixappended,ifthisFormhasa prefixset. Subclassesmaywishtooverride. """ return'%s-%s'%(self.prefix,field_name)ifself.prefixelsefield_name defadd_initial_prefix(self,field_name): """ Adda'initial'prefixforcheckingdynamicinitialvalues """ return'initial-%s'%self.add_prefix(field_name) def_html_output(self,normal_row,error_row,row_ender,help_text_html,errors_on_separate_row): "HelperfunctionforoutputtingHTML.Usedbyas_table(),as_ul(),as_p()." top_errors=self.non_field_errors()#Errorsthatshouldbedisplayedaboveallfields. output,hidden_fields=[],[] forname,fieldinself.fields.items(): html_class_attr='' bf=self[name] #Escapeandcacheinlocalvariable. bf_errors=self.error_class([conditional_escape(error)forerrorinbf.errors]) ifbf.is_hidden: ifbf_errors: top_errors.extend( [_('(Hiddenfield%(name)s)%(error)s')%{'name':name,'error':force_text(e)} foreinbf_errors]) hidden_fields.append(six.text_type(bf)) else: #Createa'class="..."'attributeiftherowshouldhaveany #CSSclassesapplied. css_classes=bf.css_classes() ifcss_classes: html_class_attr='class="%s"'%css_classes iferrors_on_separate_rowandbf_errors: output.append(error_row%force_text(bf_errors)) ifbf.label: label=conditional_escape(force_text(bf.label)) label=bf.label_tag(label)or'' else: label='' iffield.help_text: help_text=help_text_html%force_text(field.help_text) else: help_text='' output.append(normal_row%{ 'errors':force_text(bf_errors), 'label':force_text(label), 'field':six.text_type(bf), 'help_text':help_text, 'html_class_attr':html_class_attr, 'css_classes':css_classes, 'field_name':bf.html_name, }) iftop_errors: output.insert(0,error_row%force_text(top_errors)) ifhidden_fields:#Insertanyhiddenfieldsinthelastrow. str_hidden=''.join(hidden_fields) ifoutput: last_row=output[-1] #Chopoffthetrailingrow_ender(e.g.'')and #insertthehiddenfields. ifnotlast_row.endswith(row_ender): #Thiscanhappenintheas_p()case(andpossiblyothers #thatuserswrite):ifthereareonlytoperrors,wemay #notbeabletoconscriptthelastrowforourpurposes, #soinsertanew,emptyrow. last_row=(normal_row%{ 'errors':'', 'label':'', 'field':'', 'help_text':'', 'html_class_attr':html_class_attr, 'css_classes':'', 'field_name':'', }) output.append(last_row) output[-1]=last_row[:-len(row_ender)]+str_hidden+row_ender else: #Iftherearen'tanyrowsintheoutput,justappendthe #hiddenfields. output.append(str_hidden) returnmark_safe('\n'.join(output)) defas_table(self): "ReturnsthisformrenderedasHTMLs--excludingthe ." returnself._html_output( normal_row='
', error_row=' %(label)s %(errors)s%(field)s%(help_text)s ', row_ender='', help_text_html=' %s %s', errors_on_separate_row=False) defas_ul(self): "ReturnsthisformrenderedasHTML s--excludingthe ." returnself._html_output( normal_row='
%(errors)s%(label)s%(field)s%(help_text)s ', error_row='%s ', row_ender='', help_text_html='%s', errors_on_separate_row=False) defas_p(self): "ReturnsthisformrenderedasHTML s." returnself._html_output( normal_row='
%(label)s%(field)s%(help_text)s
', error_row='%s', row_ender='', help_text_html='%s', errors_on_separate_row=True) defnon_field_errors(self): """ ReturnsanErrorListoferrorsthataren'tassociatedwithaparticular field--i.e.,fromForm.clean().ReturnsanemptyErrorListifthere arenone. """ returnself.errors.get(NON_FIELD_ERRORS,self.error_class(error_class='nonfield')) defadd_error(self,field,error): """ Updatethecontentof`self._errors`. The`field`argumentisthenameofthefieldtowhichtheerrors shouldbeadded.IfitsvalueisNonetheerrorswillbetreatedas NON_FIELD_ERRORS. The`error`argumentcanbeasingleerror,alistoferrors,ora dictionarythatmapsfieldnamestolistsoferrors.Whatwedefineas an"error"canbeeitherasimplestringoraninstanceof ValidationErrorwithitsmessageattributesetandwhatwedefineas listordictionarycanbeanactual`list`or`dict`oraninstance ofValidationErrorwithits`error_list`or`error_dict`attributeset. If`error`isadictionary,the`field`argument*must*beNoneand errorswillbeaddedtothefieldsthatcorrespondtothekeysofthe dictionary. """ ifnotisinstance(error,ValidationError): #NormalizetoValidationErrorandletitsconstructor #dothehardworkofmakingsenseoftheinput. error=ValidationError(error) ifhasattr(error,'error_dict'): iffieldisnotNone: raiseTypeError( "Theargument`field`mustbe`None`whenthe`error`" "argumentcontainserrorsformultiplefields." ) else: error=error.error_dict else: error={fieldorNON_FIELD_ERRORS:error.error_list} forfield,error_listinerror.items(): iffieldnotinself.errors: iffield!=NON_FIELD_ERRORSandfieldnotinself.fields: raiseValueError( "'%s'hasnofieldnamed'%s'."%(self.__class__.__name__,field)) iffield==NON_FIELD_ERRORS: self._errors[field]=self.error_class(error_class='nonfield') else: self._errors[field]=self.error_class() self._errors[field].extend(error_list) iffieldinself.cleaned_data: delself.cleaned_data[field] defhas_error(self,field,code=None): ifcodeisNone: returnfieldinself.errors iffieldinself.errors: forerrorinself.errors.as_data()[field]: iferror.code==code: returnTrue returnFalse deffull_clean(self): """ Cleansallofself.dataandpopulatesself._errorsand self.cleaned_data. """ self._errors=ErrorDict() ifnotself.is_bound:#Stopfurtherprocessing. return self.cleaned_data={} #Iftheformispermittedtobeempty,andnoneoftheformdatahas #changedfromtheinitialdata,shortcircuitanyvalidation. ifself.empty_permittedandnotself.has_changed(): return self._clean_fields() self._clean_form() self._post_clean() def_clean_fields(self): forname,fieldinself.fields.items(): #value_from_datadict()getsthedatafromthedatadictionaries. #Eachwidgettypeknowshowtoretrieveitsowndata,becausesome #widgetssplitdataoverseveralHTMLfields. iffield.disabled: value=self.get_initial_for_field(field,name) else: value=field.widget.value_from_datadict(self.data,self.files,self.add_prefix(name)) try: ifisinstance(field,FileField): initial=self.get_initial_for_field(field,name) value=field.clean(value,initial) else: value=field.clean(value) self.cleaned_data[name]=value ifhasattr(self,'clean_%s'%name): value=getattr(self,'clean_%s'%name)() self.cleaned_data[name]=value exceptValidationErrorase: self.add_error(name,e) def_clean_form(self): try: cleaned_data=self.clean() exceptValidationErrorase: self.add_error(None,e) else: ifcleaned_dataisnotNone: self.cleaned_data=cleaned_data def_post_clean(self): """ Aninternalhookforperformingadditionalcleaningafterformcleaning iscomplete.Usedformodelvalidationinmodelforms. """ pass defclean(self): """ Hookfordoinganyextraform-widecleaningafterField.clean()hasbeen calledoneveryfield.AnyValidationErrorraisedbythismethodwill notbeassociatedwithaparticularfield;itwillhaveaspecial-case associationwiththefieldnamed'__all__'. """ returnself.cleaned_data defhas_changed(self): """ ReturnsTrueifdatadiffersfrominitial. """ returnbool(self.changed_data) @cached_property defchanged_data(self): data=[] forname,fieldinself.fields.items(): prefixed_name=self.add_prefix(name) data_value=field.widget.value_from_datadict(self.data,self.files,prefixed_name) ifnotfield.show_hidden_initial: #UsetheBoundField'sinitialasthisisthevaluepassedto #thewidget. initial_value=self[name].initial else: initial_prefixed_name=self.add_initial_prefix(name) hidden_widget=field.hidden_widget() try: initial_value=field.to_python(hidden_widget.value_from_datadict( self.data,self.files,initial_prefixed_name)) exceptValidationError: #Alwaysassumedatahaschangedifvalidationfails. data.append(name) continue iffield.has_changed(initial_value,data_value): data.append(name) returndata @property defmedia(self): """ Provideadescriptionofallmediarequiredtorenderthewidgetsonthisform """ media=Media() forfieldinself.fields.values(): media=media+field.widget.media returnmedia defis_multipart(self): """ ReturnsTrueiftheformneedstobemultipart-encoded,i.e.ithas FileInput.Otherwise,False. """ forfieldinself.fields.values(): iffield.widget.needs_multipart_form: returnTrue returnFalse defhidden_fields(self): """ ReturnsalistofalltheBoundFieldobjectsthatarehiddenfields. Usefulformanualformlayoutintemplates. """ return[fieldforfieldinselfiffield.is_hidden] defvisible_fields(self): """ ReturnsalistofBoundFieldobjectsthataren'thiddenfields. Theoppositeofthehidden_fields()method. """ return[fieldforfieldinselfifnotfield.is_hidden] defget_initial_for_field(self,field,field_name): """ Returninitialdataforfieldonform.Useinitialdatafromtheform orthefield,inthatorder.Evaluatecallablevalues. """ value=self.initial.get(field_name,field.initial) ifcallable(value): value=value() returnvalue classForm(six.with_metaclass(DeclarativeFieldsMetaclass,BaseForm)): "AcollectionofFields,plustheirassociateddata." #ThisisaseparateclassfromBaseForminordertoabstracttheway #self.fieldsisspecified.Thisclass(Form)istheonethatdoesthe #fancymetaclassstuffpurelyforthesemanticsugar--itallowsone #todefineaformusingdeclarativesyntax. #BaseFormitselfhasnowayofdesignatingself.fields.
抛开其他的代码,我们之关注我们需要的东西
1首先数据的验证通过的是is_vaild方法,它下面有以下东西
returnself.is_boundandnotself.errors 对照以下也就是is_bound不能为空,并且errors方法返回的为空,则通过验证
2我们找到errors方法,
@property deferrors(self): "ReturnsanErrorDictforthedataprovidedfortheform" ifself._errorsisNone: self.full_clean()#找到full_clean returnself._errors
3找到full_clean方法
deffull_clean(self): """ Cleansallofself.dataandpopulatesself._errorsand self.cleaned_data. """ self._errors=ErrorDict()#先赋一个空的错误字典 ifnotself.is_bound:#Stopfurtherprocessing. return self.cleaned_data={}#定义一个空的cleaned_data字典 #Iftheformispermittedtobeempty,andnoneoftheformdatahas #changedfromtheinitialdata,shortcircuitanyvalidation. ifself.empty_permittedandnotself.has_changed(): return #执行下面三种方法 self._clean_fields() self._clean_form() self._post_clean()
4 找到_clean_fields方法
def_clean_fields(self): forname,fieldinself.fields.items():#依次遍历字段 #value_from_datadict()getsthedatafromthedatadictionaries. #Eachwidgettypeknowshowtoretrieveitsowndata,becausesome #widgetssplitdataoverseveralHTMLfields. iffield.disabled: value=self.get_initial_for_field(field,name) else: value=field.widget.value_from_datadict(self.data,self.files,self.add_prefix(name)) try: ifisinstance(field,FileField): initial=self.get_initial_for_field(field,name) value=field.clean(value,initial) else: value=field.clean(value) self.cleaned_data[name]=value#通过自定义和django里面定义的方法后,将它加入到cleand_data字典中 ifhasattr(self,'clean_%s'%name):#判断是否有自定义的局部钩子函数 value=getattr(self,'clean_%s'%name)()#通过了局部钩子则返回数据 self.cleaned_data[name]=value#将数据加入cleaned_data exceptValidationErrorase: self.add_error(name,e)#错误的话执行add_error
5找到add_error
self._errors[field].extend(error_list)#将错误信息加入_errors iffieldinself.cleaned_data: delself.cleaned_data[field]#删除cleaned_data中这条数据,之前是通过自定义方法加入的,通不过钩子函数
6回到上面执行 self._clean_form()
def_clean_form(self): try: cleaned_data=self.clean()#接着执行clean()全局钩子 exceptValidationErrorase: self.add_error(None,e) else: ifcleaned_dataisnotNone: self.cleaned_data=cleaned_data
7接着查看全局钩子 clean,它只有一个返回的数据,因此我们可以自定义一个
defclean(self): returnself.cleaned_data#注意返回的数据和局部钩子的区别
8最后查看_post_clean,说白了就是什么都没有
def_post_clean(self): pass
以上是源码内部执行的顺序,下面我们来看一个例子
1自定义判断字段
2自定义局部钩子
3自定义全局钩子
4继承并使用
5.1在模板中显示一
上面的代码form_obj.errors.all_error 也可以改成 {{form_obj.non_field_errors.0}}
5.2在模板中显示二
6在浏览器上面看效果
其他:
我们在forms组件中处理的不同情况
希望本文所述对大家基于Django框架的Python程序设计有所帮助。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。