Search code examples
pythondjango-templatesdjango-formsdjango-widgetdjango-models

Django MultiWidget Phone Number Field


I want to create a field for phone number input that has 2 text fields (size 3, 3, and 4 respectively) with the common "(" ")" "-" delimiters. Below is my code for the field and the widget, I'm getting the following error when trying to iterate the fields in my form during initial rendering (it happens when the for loop gets to my phone number field):

Caught an exception while rendering: 'NoneType' object is unsubscriptable

class PhoneNumberWidget(forms.MultiWidget):
    def __init__(self,attrs=None):
        wigs = (forms.TextInput(attrs={'size':'3','maxlength':'3'}),\
                forms.TextInput(attrs={'size':'3','maxlength':'3'}),\
                forms.TextInput(attrs={'size':'4','maxlength':'4'}))
        super(PhoneNumberWidget, self).__init__(wigs, attrs)

    def decompress(self, value):
        return value or None

    def format_output(self, rendered_widgets):
        return '('+rendered_widgets[0]+')'+rendered_widgets[1]+'-'+rendered_widgets[2]

class PhoneNumberField(forms.MultiValueField):
    widget = PhoneNumberWidget
    def __init__(self, *args, **kwargs):
        fields=(forms.CharField(max_length=3), forms.CharField(max_length=3), forms.CharField(max_length=4))
        super(PhoneNumberField, self).__init__(fields, *args, **kwargs)
    def compress(self, data_list):
        if data_list[0] in fields.EMPTY_VALUES or data_list[1] in fields.EMPTY_VALUES or data_list[2] in fields.EMPTY_VALUES:
            raise fields.ValidateError(u'Enter valid phone number')
        return data_list[0]+data_list[1]+data_list[2]

class AdvertiserSumbissionForm(ModelForm):
    business_phone_number = PhoneNumberField(required=True)

Solution

  • 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:

    class PhoneNumberField(USPhoneNumberField):
        def clean(self, value):
            super(USPhoneNumberField, self).clean(value)
            if value in EMPTY_VALUES:
                return u''
            value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
            m = phone_digits_re.search(value)
            if m:
                return u'%s%s%s' % (m.group(1), m.group(2), m.group(3))
            raise ValidationError(self.error_messages['invalid'])