2011-10-30 10 views
7

djangoビューでカスタムフォームフィールドを初期化する方法がわかりません。例えばDjangoカスタムフォームフィールドの初期データ

:上記の例の支払いフォームでhttp://djangosnippets.org/snippets/907/

from datetime import date, datetime 
from calendar import monthrange 

class CreditCardField(forms.IntegerField): 
    @staticmethod 
    def get_cc_type(number): 
     number = str(number) 
     #group checking by ascending length of number 
     if len(number) == 13: 
      if number[0] == "4": 
       return "Visa" 
     return "Unknown" 

    def clean(self, value): 
     if value and (len(value) < 13 or len(value) > 16): 
      raise forms.ValidationError("Please enter in a valid "+\ 
       "credit card number.") 
     elif self.get_cc_type(value) not in ("Visa", "MasterCard", 
              "American Express"): 
      raise forms.ValidationError("Please enter in a Visa, "+\ 
       "Master Card, or American Express credit card number.") 
     return super(CreditCardField, self).clean(value) 

class CCExpWidget(forms.MultiWidget): 
    """ Widget containing two select boxes for selecting the month and year""" 
    def decompress(self, value): 
     return [value.month, value.year] if value else [None, None] 

    def format_output(self, rendered_widgets): 
     html = u'/'.join(rendered_widgets) 
     return u'<span style="white-space: nowrap">%s</span>' % html 


class CCExpField(forms.MultiValueField): 
    EXP_MONTH = [(x, x) for x in xrange(1, 13)] 
    EXP_YEAR = [(x, x) for x in xrange(date.today().year, 
             date.today().year + 15)] 
    default_error_messages = { 
     'invalid_month': u'Enter a valid month.', 
     'invalid_year': u'Enter a valid year.', 
    } 

    def __init__(self, *args, **kwargs): 
     errors = self.default_error_messages.copy() 
     if 'error_messages' in kwargs: 
      errors.update(kwargs['error_messages']) 
     fields = (
      forms.ChoiceField(choices=self.EXP_MONTH, 
       error_messages={'invalid': errors['invalid_month']}), 
      forms.ChoiceField(choices=self.EXP_YEAR, 
       error_messages={'invalid': errors['invalid_year']}), 
     ) 
     super(CCExpField, self).__init__(fields, *args, **kwargs) 
     self.widget = CCExpWidget(widgets = 
      [fields[0].widget, fields[1].widget]) 

    def clean(self, value): 
     exp = super(CCExpField, self).clean(value) 
     if date.today() > exp: 
      raise forms.ValidationError(
      "The expiration date you entered is in the past.") 
     return exp 

    def compress(self, data_list): 
     if data_list: 
      if data_list[1] in forms.fields.EMPTY_VALUES: 
       error = self.error_messages['invalid_year'] 
       raise forms.ValidationError(error) 
      if data_list[0] in forms.fields.EMPTY_VALUES: 
       error = self.error_messages['invalid_month'] 
       raise forms.ValidationError(error) 
      year = int(data_list[1]) 
      month = int(data_list[0]) 
      # find last day of the month 
      day = monthrange(year, month)[1] 
      return date(year, month, day) 
     return None 


class PaymentForm(forms.Form): 
    number = CreditCardField(required = True, label = "Card Number") 
    holder = forms.CharField(required = True, label = "Card Holder Name", 
     max_length = 60) 
    expiration = CCExpField(required = True, label = "Expiration") 
    ccv_number = forms.IntegerField(required = True, label = "CCV Number", 
     max_value = 9999, widget = forms.TextInput(attrs={'size': '4'})) 

    def __init__(self, *args, **kwargs): 
     self.payment_data = kwargs.pop('payment_data', None) 
     super(PaymentForm, self).__init__(*args, **kwargs) 

    def clean(self): 
     cleaned = super(PaymentForm, self).clean() 
     if not self.errors: 
      result = self.process_payment() 
      if result and result[0] == 'Card declined': 
       raise forms.ValidationError('Your credit card was declined.') 
      elif result and result[0] == 'Processing error': 
       raise forms.ValidationError(
        'We encountered the following error while processing '+\ 
        'your credit card: '+result[1]) 
     return cleaned 

    def process_payment(self): 
     if self.payment_data: 
      # don't process payment if payment_data wasn't set 
      datadict = self.cleaned_data 
      datadict.update(self.payment_data) 

      from virtualmerchant import VirtualMerchant 
      vmerchant = VirtualMerchant(datadict) 

      return vmerchant.process_virtualmerchant_payment() 

、どのようにPaymentForm.expirationフィールドに初期データを渡すでしょうか?

私はあなたが行うことができます知っている:

c = PaymentForm({'number':'1234567890', 'holder':'Bob Barker','ccv_number':'123'}) 

はしかし、どのようなここで実装一つとして、カスタムフィールドにデータを渡すのですか?

+1

私は分かりませんなぜあなたはこれが他の分野とも異なると思いますか?あなたがコメントした[私の他の回答](http://stackoverflow.com/questions/936376/prepopulate-django-non-model-form/936622#936622)に記載されているように、単にフォームをインスタンス化するときに 'initial'を使用してください。 –

+0

@DanielRoseman:PaymentForm.expirationに初期データをあらかじめ入力するために、上記で定義したPaymentFormに何を渡す必要がありますか?私はc = PaymentForm({'expiration': '01/2011'})と他の組み合わせを試してみましたが、私はこの質問をしています。 – Chris

答えて

7

あなたはそれがカスタムフィールド

https://code.djangoproject.com/browser/django/trunk/django/forms/fields.py#L45

だ場合でもそうあなただけのコンストラクタを上書きすることができるはずという設定ので、すべてのフィールドが「初期」属性を持っている:

class PaymentForm(forms.Form): 
    def __init__(self, exp = None, *args, **kwargs): 
     super(PaymentForm, self).__init__(*args, **kwargs) 
     if exp: 
      self.fields['expiration'].initial = exp 

とあなたの見解では、必要なデータを渡すことができます:

form = PaymentForm(exp=...) 
+0

それは理にかなっていますが、CCExpFieldがそのデータをどのように取得するのか分かりません。あなたの答えでは、私の支払いフォームが初期化されたときに引数 "exp"がチェックされ、渡された場合、これをPaymentForm.expirationフィールドに渡します。この時点で、CCExpFieldであるPaymentForm.expirationはどのようにしてそのデータを2つのcharフィールドに取得しますか? – Chris

+1

CCExpFieldには、ここでデータが与えられます。self.fields ['expiration']。initial = expここでフィールドオブジェクトの 'initial'属性が設定されています。以前に何も保存されていない場合、これは後でウィジェットに供給されて値として表示されます。 –

関連する問題