6

Je souhaite créer un champ pour l'entrée du numéro de téléphone comportant 2 champs de texte (taille 3, 3 et 4 respectivement) avec les délimiteurs communs "(" ")" "-. Ci-dessous est mon code pour le champ et le widget, j'obtiens l'erreur suivante en essayant d'itérer les champs dans mon formulaire pendant le rendu initial (cela arrive quand la boucle for arrive à mon champ de numéro de téléphone):Champ de numéro de téléphone Django MultiWidget

une exception tout en rendant: objet « NoneType » est 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

une raison quelconque vous n'êtes pas seulement nous utiliser. models.PhoneNumberField et us.forms.USPhoneNumberField? Très pratique si vous avez des numéros d'ophone américains. http://docs.djangoproject.com/fr/dev/ref/contrib/localflavor/#united-states-of-america-us – hughdbrown

+0

Il serait utile de savoir où le retraçage se produisait - c.-à-d. donner plus de détails que cela une ligne. –

+0

En référence à la suggestion faite par @hughdbrown Django-Localflavor a été déplacé dans Django 1.5 il réside maintenant à https://github.com/django/django-localflavor – davelupt

Répondre

1

Je conseille de hughdbrown a pris Modifiés USPhoneNumberField pour faire ce que je dois. La raison pour laquelle je ne l'ai pas utilisé initialement était qu'il stocke les numéros de téléphone comme XXX-XXX-XXXX dans la base de données, je les stocke comme XXXXXXXXXX. Donc, je montais sur-la méthode propre:

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

Il utilise widget.value_from_datadict() pour formater les données donc pas besoin de sous-classe un champ, il suffit d'utiliser la USPhoneNumberField existante. Les données sont stockées dans db comme 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) 

utilisation sous une forme comme ceci:

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

Parfois, il est utile de résoudre le problème d'origine plutôt que de tout refaire. L'erreur que vous avez, "Pris une exception lors du rendu: l'objet 'NoneType' est insubmersible" a un indice. Il y a une valeur renvoyée comme None (unsubscriptible) lorsqu'une valeur indicative est attendue. La fonction de décompression dans la classe PhoneNumberWidget est un coupable probable. Je suggère de retourner [] au lieu de None.

3

Je pense que le value_from_datadict code() peut être simplifiée:


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 

La méthode value_from_datadict() pour MultiValueWidget fait déjà les éléments suivants:


    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

cela fonctionne bien mais je reçois une erreur dans Django 1.3 dans le Fonction value_from_datadict car la variable values ​​n'est pas un tuple mais une liste. J'ai dû convertir la liste en utilisant tuple (valeurs) pour le faire fonctionner correctement. J'ai édité la réponse en conséquence. – bchhun

Questions connexes