Django Multiwidget Phone Number Field
Solution 1:
This uses widget.value_from_datadict()
to format the data so no need to subclass a field, just use the existing USPhoneNumberField
. Data is stored in db like XXX-XXX-XXXX.
from django import forms
classUSPhoneNumberMultiWidget(forms.MultiWidget):
"""
A Widget that splits US Phone number input into three <input type='text'> boxes.
"""def__init__(self,attrs=None):
widgets = (
forms.TextInput(attrs={'size':'3','maxlength':'3', 'class':'phone'}),
forms.TextInput(attrs={'size':'3','maxlength':'3', 'class':'phone'}),
forms.TextInput(attrs={'size':'4','maxlength':'4', 'class':'phone'}),
)
super(USPhoneNumberMultiWidget, self).__init__(widgets, attrs)
defdecompress(self, value):
if value:
return value.split('-')
return (None,None,None)
defvalue_from_datadict(self, data, files, name):
value = [u'',u'',u'']
# look for keys like name_1, get the index from the end# and make a new list for the string replacement valuesfor d infilter(lambda x: x.startswith(name), data):
index = int(d[len(name)+1:])
value[index] = data[d]
if value[0] == value[1] == value[2] == u'':
returnNonereturnu'%s-%s-%s' % tuple(value)
use in a form like so:
from django.contrib.localflavor.us.forms import USPhoneNumberField
classMyForm(forms.Form):
phone =USPhoneNumberField(label="Phone", widget=USPhoneNumberMultiWidget())
Solution 2:
I think the value_from_datadict() code can be simplified to:
classUSPhoneNumberMultiWidget(forms.MultiWidget):
"""
A Widget that splits US Phone number input into three boxes.
"""def__init__(self,attrs=None):
widgets = (
forms.TextInput(attrs={'size':'3','maxlength':'3', 'class':'phone'}),
forms.TextInput(attrs={'size':'3','maxlength':'3', 'class':'phone'}),
forms.TextInput(attrs={'size':'4','maxlength':'4', 'class':'phone'}),
)
super(USPhoneNumberMultiWidget, self).__init__(widgets, attrs)
defdecompress(self, value):
if value:
return value.split('-')
return [None,None,None]
defvalue_from_datadict(self, data, files, name):
values = super(USPhoneNumberMultiWidget, self).value_from_datadict(data, files, name)
returnu'%s-%s-%s' % values
The value_from_datadict() method for MultiValueWidget already does the following:
defvalue_from_datadict(self, data, files, name):
return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget inenumerate(self.widgets)]
Solution 3:
I took hughdbrown's advise and modified USPhoneNumberField to do what I need. The reason I didn't use it initially was that it stores phone numbers as XXX-XXX-XXXX in the DB, I store them as XXXXXXXXXX. So I over-rode the clean method:
classPhoneNumberField(USPhoneNumberField):
defclean(self, value):
super(USPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
returnu''
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
m = phone_digits_re.search(value)
if m:
returnu'%s%s%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(self.error_messages['invalid'])
Solution 4:
Sometimes it is useful to fix the original problem rather than redoing everything. The error you got, "Caught an exception while rendering: 'NoneType' object is unsubscriptable" has a clue. There is a value returned as None(unsubscriptable) when a subscriptable value is expected. The decompress function in PhoneNumberWidget class is a likely culprit. I would suggest returning [] instead of None.
Post a Comment for "Django Multiwidget Phone Number Field"