fromdjango.formsimportValidationErrorfromdjango.forms.fieldsimportField,EMPTY_VALUESfromdjango.utils.encodingimportsmart_unicodefromdjango.utils.translationimportugettext_lazyas_importreimporttypesclassUKPhoneNumberField(Field):default_error_messages={'partial':_('Phone number must include an area code.'),'non_uk':_('Phone number must be a UK number.'),'length_range':_('Phone number must be between %d and %d digits'),'length':_('Phone number must be %d digits'),'reject_premium':_('Phone number can\'t be premium rate.'),'reject_service':_('Phone number can\'t be a service number.')}number_specs=((r'^01(1\d|\d1)',None,(4,3,4)),(r'^016977\d{4}$',None,(6,4)),(r'^01(3873|5(242|39[456])|697[347]|768[347]|9467)',None,(6,5)),(r'^01',None,(5,(5,6))),(r'^0500\d{6}$',None,(4,6)),(r'^0(2[03489]|5[56])',None,(3,4,4)),(r'^03[0347]',None,(4,3,4)),(r'^07([1-57-9]|624)',None,(5,6)),(r'^070','premium',(3,6)),(r'^08(001111|454647)$',None,(4,4)),(r'^0800\d{6}$',None,(4,6)),(r'^08[047]\d{8}$',None,(4,3,4)),(r'^09','premium',(4,3,4)),(r'^11[68]','service',(3,3)),(r'^999$','service',(3,)),(r'^1','service',None),)def__init__(self,*args,**kwargs):self.reject=set(kwargs.pop('reject',()))super(UKPhoneNumberField,self).__init__(*args,**kwargs)defclean(self,value):super(UKPhoneNumberField,self).clean(value)value=smart_unicode(value)ifvalueinEMPTY_VALUES:returnu''value=re.sub(r'[^0-9+]',r'',value)value=re.sub(r'(?<!^)\+',r'',value)value=re.sub(r'^\+44(?=[1-9])',r'0',value)value=re.sub(r'^\+44(?=0)',r'',value)ifre.match(r'^(\+(?!44)|00)',value):raiseValidationError(self.error_messages['non_uk'])number_spec=self.get_number_spec(value)ifnotnumber_spec:raiseValidationError(self.error_messages['partial'])ifnumber_spec[0]inself.reject:raiseValidationError(self.error_messages['reject_%s'%number_spec[0]])ifnotself.valid_length(value,number_spec):min_length,max_length=self.spec_lengths(number_spec)ifmin_length==max_length:raiseValidationError(self.error_messages['length']%min_length)else:raiseValidationError(self.error_messages['length_range']%(min_length,max_length))returnself.format_number(value,number_spec)defget_number_spec(self,value):fornumber_specinself.number_specs:ifre.match(number_spec[0],value):returnnumber_spec[1:]returnNonedefspec_lengths(self,number_spec):ifnotnumber_spec[1]:returnNone,Noneiftype(number_spec[1][-1])==types.TupleType:min_length,max_length=number_spec[1][-1]total=sum(number_spec[1][:-1])min_length+=totalmax_length+=totalelse:min_length=max_length=sum(number_spec[1])returnmin_length,max_lengthdefvalid_length(self,value,number_spec):min_length,max_length=self.spec_lengths(number_spec)ifmin_lengthisnotNoneandlen(value)<min_length:returnFalseifmax_lengthisnotNoneandlen(value)>max_length:returnFalsereturnTruedefformat_number(self,value,number_spec):ifnumber_spec[1]isNone:components=(value,)else:components=[]position=0last_index=len(number_spec)-1forindex,chunkinenumerate(number_spec[1]):ifindex==last_index:components.append(value[position:])else:components.append(value[position:position+chunk])position+=chunkreturn' '.join(components)