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=' %(label)s %(errors)s%(field)s%(help_text)s ',
error_row='%s ',
row_ender='',
help_text_html='
%s',
errors_on_separate_row=False)
defas_ul(self):
"ReturnsthisformrenderedasHTMLs--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):
"ReturnsthisformrenderedasHTMLs."
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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。