2011-10-30 47 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

我不明白为什么你认为这会和其他领域有所不同。在实例化表单时,只需使用'initial',如你所评论的[我的其他答案](http://stackoverflow.com/questions/936376/prepopulate-django-non-model-form/936622#936622)中所述。 –

+0

@DanielRoseman:我会传递给上面定义的PaymentForm以预先填充PaymentForm.expiration和初始数据?我试过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个字符字段。 – Chris

+1

CCExpField在此处给出数据:self.fields ['expiration']。initial = exp设置字段对象的'initial'属性。如果以前没有保存任何内容,则稍后将这些内容提供给小部件以显示值。 –

相关问题