2011-10-30 31 views
7

Tôi gặp sự cố khi hiểu cách khởi tạo trường biểu mẫu tùy chỉnh trong chế độ xem django.Dữ liệu ban đầu của trường biểu mẫu tùy chỉnh Django

Ví dụ: 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() 

Trong hình thức thanh toán ví dụ trên, làm thế nào bạn sẽ truyền dữ liệu ban đầu để lĩnh vực PaymentForm.expiration?

Tôi biết bạn có thể làm:

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

Tuy nhiên, làm thế nào để bạn vượt qua dữ liệu vào một lĩnh vực tùy chỉnh như một thực hiện ở đây?

+1

Tôi không hiểu tại sao bạn nghĩ rằng điều này sẽ khác với bất kỳ lĩnh vực nào khác. Chỉ cần sử dụng 'initial' khi khởi tạo biểu mẫu, như được đề cập trong [câu trả lời khác của tôi] (http://stackoverflow.com/questions/936376/prepopulate-django-non-model-form/936622#936622) mà bạn đã nhận xét. –

+0

@DanielRoseman: Tôi sẽ chuyển cho PaymentForm được định nghĩa ở trên để điền trước PaymentForm.expiration với dữ liệu ban đầu? Tôi đã thử c = PaymentForm ({'hết hạn': '01/2011'}) và các kết hợp khác và không thể làm cho nó được chuẩn bị trước, đó là lý do tại sao tôi hỏi câu hỏi này. – Chris

Trả lời

7

Tất cả các lĩnh vực có một thuộc tính 'đầu tiên' để bạn thiết lập rằng ngay cả khi đó là một lĩnh vực tùy chỉnh

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

vì vậy bạn nên chỉ có thể ghi đè lên các nhà xây dựng:

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

và trong chế độ xem của mình, bạn có thể chuyển dữ liệu được yêu cầu:

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

Điều đó có ý nghĩa nhưng làm thế nào để CCExpField nhận được dữ liệu đó là những gì tôi không hiểu. Trong câu trả lời của bạn, hình thức thanh toán của tôi khi khởi tạo kiểm tra cho một đối số "điểm kinh nghiệm" và nếu được thông qua, chuyển này vào trường PaymentForm.expiration. Tại thời điểm này như thế nào PaymentForm.expiration đó là một CCExpField nhận được dữ liệu đó vào 2 lĩnh vực char của nó. – Chris

+1

CCExpField được cung cấp dữ liệu ở đây: self.fields ['expiration']. Initial = exp nơi thuộc tính 'initial' của đối tượng field được thiết lập. Điều này sau đó được cung cấp cho widget sẽ được hiển thị dưới dạng giá trị nếu không có gì được lưu trước đó. –

Các vấn đề liên quan