2011-10-30 21 views
7

Tengo problemas para entender cómo inicializar un campo de formulario personalizado en una vista django.Datos iniciales del campo de formulario personalizado de Django

Por ejemplo: 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() 

En el ejemplo de forma de pago anterior, ¿cómo pasar datos iniciales a campo PaymentForm.expiration?

sé que puede hacer:

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

Sin embargo, ¿cómo se dejan pasar los datos a un campo personalizado como el implementado aquí?

+1

No entiendo por qué piensas que esto sería diferente a cualquier otro campo. Simplemente use 'initial' al crear una instancia del formulario, como se menciona en [mi otra respuesta] (http://stackoverflow.com/questions/936376/prepopulate-django-non-model-form/936622#936622) que ha comentado. –

+0

@DanielRoseman: ¿Qué pasaría a PaymentForm definido anteriormente para rellenar PaymentForm.expiration con los datos iniciales? Intenté c = PaymentForm ({'expiration': '01/2011'}) y otras combinaciones y no pude conseguir que se llene previamente, razón por la cual hago esta pregunta. – Chris

Respuesta

7

todos los campos tienen un atributo 'inicial' por lo que se establece que, incluso si se trata de un campo personalizado

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

por lo que sólo debe ser capaz de sobreescribir el constructor:

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

y En su vista puede pasar los datos requeridos:

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

Eso tiene sentido, pero cómo CCExpField obtiene esos datos es lo que no entiendo. En su respuesta, mi formulario de pago cuando se inicializa comprueba un argumento "exp" y, si se aprueba, lo pasa al campo PaymentForm.expiration. En este punto, ¿cómo PaymentForm.expiration que es un CCExpField obtiene esos datos en sus 2 campos char. – Chris

+1

El CCExpField recibe los datos aquí: self.fields ['expiration']. Initial = exp donde se establece el atributo 'inicial' del objeto de campo. Esto se envía luego al widget para que se muestre como el valor si no se guardó nada previamente. –

Cuestiones relacionadas