Reputation: 26647
My input is rather strangely formatted but according to spec:
User should input the ID in 4 fields(!) where the id is the form 460 000 005 001 where 46 is a country code and the right part is the appengine ID of the user. Now I want to add validation to this field but I can't do it with wtforms. Here is my form class:
class RegisterWTForm(Form):
soc_sec = TextField(_('Soc security number'), [validators.Regexp('^[0-9]+$',
message=_('This is not a social security number, please see the example and try again'
)), validators.Required(message=_('Social security number is required')), unique_soc_sec], widget=MyTextInput())
email = TextField(_('Email'),
[validators.Required(message=_('Email is required'
)),
validators.Email(message=_('Your email is invalid'
))], widget=MyTextInput())
def validate_soc_sec(form, field):
if len(field.data) != 10:
raise ValidationError(_('Soc sec must be 10 characters'
))
def validate_email(form, field):
if len(field.data) > 60:
raise ValidationError(_('Email must be less than 60 characters'
))
And here is how I use the variables now, they are not part of the WTForm but regular http post parameters:
def post(self):
Log1 = self.request.POST.get('Log1')
Log2 = self.request.POST.get('Log2')
Log3 = self.request.POST.get('Log3')
Log4 = self.request.POST.get('Log4')
form = RegisterWTForm(self.request.params)
if form.validate():
logging.info('validated successfully')
else:
logging.info('form did not validate')
self.render_jinja('register.html', form=form, Log1=Log1, Log2=Log2, Log3=Log3, Log4=Log4 )
return ''
email = self.request.POST.get('email')
sponsor_id = '%s%s%s' % (Log2, Log3, Log4)
if sponsor_id:
user = User.get_by_id(long(sponsor_id))
else:
return 'Sponsor with sponsor id %s does not exist' % sponsor_id
if not user:
return 'Sponsor with sponsor id %s does not exist' % sponsor_id
# make a token for a one-time login link that sets the password
# Passing password_raw=password so password will be hashed
# Returns a tuple, where first value is BOOL. If True ok, If False no new user is created
user = self.auth.store.user_model.create_user(email)
Is there a way to add my 4 variables as one variable to my WTForm and add validation there, or should I make my own custom validation for these fields? For my other fields I've made them with a red border and red text if the field does not pass validation and I'd like to do the same here but it will be a lot of logic in the presentation layer if I can't do it with the form class and must add the code to the template. Can you propose what to do?
Thank you
I could create a FormField that combines the fields but they don't render correctly and I don't need all 4 validations. Maybe you can tell me more how to make this they way I want?
class SponsorWTForm(Form):
log1 = IntegerField('log1', [validators.required()])
log2 = IntegerField('log2', [validators.required()])
log3 = IntegerField('log3', [validators.required()])
log4 = IntegerField('log4', [validators.required()])
class RegisterWTForm(Form):
sponsor_id = FormField(SponsorWTForm)
...
Upvotes: 4
Views: 2470
Reputation: 1777
It looks like WTForms solves this using field enclosures. The example at that link is for a telephone number with separate area code and number field fields which is very similar to your multi-part ID number use case.
To properly render the subform, you will have to define a custom widget. Look at the source code for ListWidget. Your widget will probably similar but simpler (as I think you just want a space between the different fields, not HTML tags). Something as simple as
return HTMLString(u' '.join([subfield() for subfield in field]))
may suit your needs. Then put widget=SingleLineWidget()
(or whatever you name your widget class) in the arguments of the FormField
constructor.
Slightly off-topic, the corresponding way to do this in Django Forms is rather different: you define custom clean and validate methods which transform your data (i.e. in this case, combining the 4 ID fields into one).
Upvotes: 5