Django MultiWidget Phone Number Field

后端 未结 4 626
执笔经年
执笔经年 2020-12-31 20:54

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 th

相关标签:
4条回答
  • 2020-12-31 21:16

    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'])
    
    0 讨论(0)
  • 2020-12-31 21:23

    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
    
    class USPhoneNumberMultiWidget(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)
    
        def decompress(self, value):
            if value:
                return value.split('-')
            return (None,None,None)
    
        def value_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 values
            for d in filter(lambda x: x.startswith(name), data):
                index = int(d[len(name)+1:]) 
                value[index] = data[d]
            if value[0] == value[1] == value[2] == u'':
                return None
            return u'%s-%s-%s' % tuple(value)
    

    use in a form like so:

    from django.contrib.localflavor.us.forms import USPhoneNumberField
    class MyForm(forms.Form):
        phone = USPhoneNumberField(label="Phone", widget=USPhoneNumberMultiWidget())
    
    0 讨论(0)
  • 2020-12-31 21:24

    I think the value_from_datadict() code can be simplified to:

    
    class USPhoneNumberMultiWidget(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)
    
        def decompress(self, value):
            if value:
                return value.split('-')
            return [None,None,None]
    
        def value_from_datadict(self, data, files, name):
            values = super(USPhoneNumberMultiWidget, self).value_from_datadict(data, files, name)
            return u'%s-%s-%s' % values
    

    The value_from_datadict() method for MultiValueWidget already does the following:

    
        def value_from_datadict(self, data, files, name):
            return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
    
    0 讨论(0)
  • 2020-12-31 21:24

    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.

    0 讨论(0)
提交回复
热议问题