2011-10-30 14 views
7

Non riesco a capire come inizializzare un campo modulo personalizzato in una vista django.Dati iniziali campo modulo personalizzato Django

Ad esempio: 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() 

Nell'esempio modulo di pagamento di cui sopra, come è possibile passare i dati iniziali a campo PaymentForm.expiration?

So che si può fare:

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

Tuttavia, come si fa a passare i dati ad un campo personalizzato come quello implementato qui?

+1

Non capisco perché pensi che questo sarebbe diverso da qualsiasi altro campo. Basta usare 'iniziale' durante l'istanziazione del modulo, come menzionato in [la mia altra risposta] (http://stackoverflow.com/questions/936376/prepopulate-django-non-model-form/936622#936622) che hai commentato. –

+0

@DanielRoseman: che cosa dovrei passare a PaymentForm definito sopra per prepopolare PaymentForm.expiration con i dati iniziali? Ho provato c = PaymentForm ({'expiration': '01/2011'}) e altre combinazioni e non sono riuscito a farlo precompilare, motivo per cui sto facendo questa domanda. – Chris

risposta

7

Tutti i campi hanno un attributo 'iniziale' in modo di impostare che, anche se si tratta di un campo personalizzato

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

così si dovrebbe solo essere in grado di sovrascrivere il costruttore:

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

e dal tuo punto di vista puoi passare i dati richiesti:

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

Questo ha senso, ma come fa CCExpField a ottenere che i dati siano quelli che non capisco. Nella tua risposta, il mio modulo di pagamento durante i controlli inizializzati per un argomento "exp" e se passato, lo passa nel campo PaymentForm.expiration. A questo punto, come fa PaymentForm.expiration, che è un CCExpField, ottiene i dati nei suoi 2 campi char. – Chris

+1

A CCExpField vengono dati i seguenti dati: self.fields ['expiration']. Initial = exp dove è impostato l'attributo 'initial' dell'oggetto field. Successivamente viene inviato al widget per essere visualizzato come valore se non è stato precedentemente salvato nulla. –

Problemi correlati