6

Ich möchte ein Feld für Telefonnummer Eingabe erstellen, die 2 Textfelder (Größe 3, 3 und 4) mit den gemeinsamen "(" ")" "-" Trennzeichen hat. Unten ist mein Code für das Feld und das Widget, ich bekomme den folgenden Fehler beim Versuch, die Felder in meinem Formular beim ersten Rendern zu wiederholen (es passiert, wenn die for-Schleife zu meinem Telefonnummernfeld gelangt):Django MultiWidget Telefonnummer Feld

Gefangen eine Ausnahme beim Rendern: ‚NoneType‘ Objekt ist 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

Gibt es Gründe, Sie sind nicht nur uns mit. models.PhoneNumberField und us.forms.USPhoneNumberField? Sehr praktisch, wenn Sie US-Telefonnummern haben. http://docs.djangoproject.com/en/dev/ref/contrib/localflavor/#united-states-of-america-us – hughdbrown

+0

Es wäre nützlich zu wissen, wo das Traceback stattgefunden hat - dh, geben Sie mehr Details als nur das eine Linie. –

+0

In Bezug auf den Vorschlag von @hughdbrown gemacht Django-Localflavor wurde in Django 1.5 ausgezogen es liegt jetzt bei https://github.com/django/django-localflavor – davelupt

Antwort

1

I. nahm hughdbrown beraten und modifizierte USPhoneNumberField zu tun, was ich brauche. Der Grund, warum ich es anfangs nicht verwendet habe, war, dass es Telefonnummern als XXX-XXX-XXXX in der Datenbank speichert, ich speichere sie als XXXXXXXXXX. So ritt ich die saubere Methode:

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

Dies verwendet widget.value_from_datadict() die Daten zu formatieren, so dass keine Notwendigkeit, ein Feld zu Unterklasse, verwenden Sie einfach die vorhandene USPhoneNumberField. Daten werden in db wie XXX-XXX-XXXX gespeichert.

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) 

Verwendung in einer Form, wie so:

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

Manchmal ist es nützlich, das ursprüngliche Problem, anstatt redoing alles zu beheben. Der Fehler, den Sie erhalten haben: "Eine Ausnahme beim Rendern abgefangen: Das Objekt 'NoneType' ist nicht abbildbar" weist auf einen Hinweis hin. Wenn ein subscriptable-Wert erwartet wird, wird ein Wert als None (nicht abzweigbar) zurückgegeben. Die Entkomprimierungsfunktion in der PhoneNumberWidget-Klasse ist wahrscheinlich ein Täter. Ich würde vorschlagen, [] anstelle von None zurückzugeben.

3

ich denke, die value_from_datadict() Code kann vereinfacht werden:


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 

Die value_from_datadict() -Methode für MultiValueWidget bereits geschieht Folgendes:


    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

das funktioniert gut, aber ich bekomme einen Fehler in Django 1.3 in der value_from_datadict-Funktion, weil die values-Variable kein Tupel ist, sondern eine Liste. Ich musste die Liste mit Tupel (Werten) konvertieren, damit es richtig funktioniert. Ich habe die Antwort entsprechend bearbeitet. – bchhun