6

Quiero crear un campo para la entrada del número de teléfono que tiene 2 campos de texto (tamaño 3, 3 y 4 respectivamente) con los delimitadores comunes "(" ")" "-". A continuación está mi código para el campo y el widget, obtengo el siguiente error al intentar repetir los campos en mi formulario durante la representación inicial (sucede cuando el bucle for llega a mi campo de número de teléfono):Django MultiWidget Número de teléfono campo

Caught una excepción al intentar mostrar: objeto 'NoneType' es 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) 
+0

algún motivo usted no está sólo nos utiliza. models.PhoneNumberField y us.forms.USPhoneNumberField? Muy conveniente si tienes números de teléfono de EE. UU. http://docs.djangoproject.com/en/dev/ref/contrib/localflavor/#united-states-of-america-us – hughdbrown

+0

Sería útil saber dónde estaba ocurriendo el rastreo, es decir, proporcionar más detalles que solo eso una línea. –

+0

En referencia a la sugerencia hecha por @hughdbrown, Django-Localflavor se movió en Django 1.5 y ahora reside en https://github.com/django/django-localflavor – davelupt

Respuesta

1

de tomé hughdbrown asesorar y modificar USPhoneNumberField a hacer lo que necesito. La razón por la que no lo usé inicialmente fue porque almacena números de teléfono como XXX-XXX-XXXX en el DB, los almaceno como XXXXXXXXXX. Así que monté sobre-el método de limpieza:

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']) 
5

Este utiliza widget.value_from_datadict() para dar formato a los datos así que no hay necesidad de una subclase de un campo, sólo tiene que utilizar el USPhoneNumberField existente. Los datos se almacenan en db como 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) 

uso en una forma de este modo:

from django.contrib.localflavor.us.forms import USPhoneNumberField 
class MyForm(forms.Form): 
    phone = USPhoneNumberField(label="Phone", widget=USPhoneNumberMultiWidget()) 
0

A veces es útil para solucionar el problema original en lugar de hacer de nuevo todo. El error que obtuvo, "Capturó una excepción durante la representación: el objeto 'NoneType' no se puede suscribir" tiene una pista. Hay un valor devuelto como None (unsubscriptable) cuando se espera un valor subscriptable. La función de descompresión en la clase PhoneNumberWidget es probablemente una culpable. Sugeriría regresar [] en lugar de None.

3

creo que el código value_from_datadict() se puede simplificar a:


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 

El método value_from_datadict() para MultiValueWidget ya se hace lo siguiente:


    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

esto funciona bien, pero me sale un error en Django 1.3 en el función value_from_datadict porque la variable de valores no es una tupla sino una lista. Tuve que convertir la lista usando tupla (valores) para que funcione correctamente. Edité la respuesta en consecuencia. – bchhun

Cuestiones relacionadas