I am having trouble understanding how to initialize a custom form field in a django view.
For example: 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()
In the above example payment form, how would you pass initial data to PaymentForm.expiration field?
I know you can do:
c = PaymentForm({'number':'1234567890', 'holder':'Bob Barker','ccv_number':'123'})
However, how do you pass data to a custom field such as the one implemented here?
All fields have an 'initial' attribute so you set that even if it's a custom field
https://code.djangoproject.com/browser/django/trunk/django/forms/fields.py#L45
so you should just be able to overwrite the 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
and in your view you can pass the required data:
form = PaymentForm(exp=...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With