6

一般的な "(" ")" "区切り文字を持つ2つのテキストフィールド(それぞれサイズ3、3、4)を持つ電話番号入力のフィールドを作成します。以下は、フィールドとウィジェットのコードです。最初のレンダリング時にフォームのフィールドを繰り返し処理しようとしたときに次のエラーが表示されます(forループが自分の電話番号フィールドに到達したときに発生します)。Django MultiWidget電話番号フィールド

キャッチレンダリング中に例外:「NoneType」オブジェクトは、私がhughdbrownのアドバイスを取って、私は必要なものを行うにはUSPhoneNumberFieldを修正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

あなただけの私たちを使用していない理由。 Model.PhoneNumberFieldとus.forms.USPhoneNumberField?米国の電話番号があれば非常に便利です。 http://docs.djangoproject.com/en/dev/ref/contrib/localflavor/#united-states-of-america-us – hughdbrown

+0

トレースバックの発生場所を知ることは有益でしょう。 1行 –

+0

@hughdbrownの提案を参考にして、Django-LocalflavorはDjango 1.5に移されました。現在はhttps://github.com/django/django-localflavor – davelupt

答えて

1

です。私が最初にそれを使用しなかった理由は、電話番号をXXX-XXX-XXXXとしてDBに格納しているため、XXXXXXXXXXとして保存します。だから私はきれいなメソッドをオーバー乗っ:

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

これは、単に既存のUSPhoneNumberFieldを使用し、そのフィールドをサブクラス化する必要がデータをフォーマットしないようにwidget.value_from_datadict()を使用しています。データは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) 

使用:

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

時にはすべてをやり直すのではなく、元の問題を解決するのに便利です。あなたが持っているエラーは、「レンダリング中に例外が発生しました: 'NoneType'オブジェクトはサブスクライブできません」という手掛かりがあります。サブスクリプト可能な値が必要な場合は、None(unsubscriptable)として返されます。 PhoneNumberWidgetクラスの解凍機能は、おそらく原因です。私はNoneの代わりに[]を返すことを提案します。

3

私はvalue_from_datadict()のコードはに単純化することができると思う:


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 

MultiValueWidgetためvalue_from_datadict()メソッドは、すでに以下のん:


    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

にありますが、これはうまくいきますが、Django 1.3でエラーが発生しました。 values_from_datadict関数は、values変数がタプルではなくリストであるために機能します。私はそれを正しく動作させるためにタプル(値)を使ってリストを変換しなければならなかった。私はそれに応じて答えを編集しました。 – bchhun