We'll start off with one of the examples from the Formish documentation.
class SimpleSchema(schemaish.Structure):
""" A simple sommets form """
email = schemaish.String(validator=validatish.All(validatish.Required(), validatish.Email()))
first_names = schemaish.String(validator=validatish.Required())
last_name = schemaish.String(validator=validatish.Required())
comments = schemaish.String()
def get_form():
""" Creates a form and assigns a widget """
form = formish.Form(SimpleSchema())
form['comments'].widget = formish.TextArea()
return form
class Root(resource.Resource):
""" Our form resource """
@resource.GET()
@templating.page('test.html')
def html(self, request, form=None):
"""
If the form is None then we get a clean form, otherwise show the
form that was passsed back from an unsuccessful POST
"""
if form is None:
form = get_form()
return {'form': form}
@resource.POST()
def POST(self, request):
"""
Get a clean form and validate it against the request data that was
submitted. Errors pass the form (with attached errors) back up to
the page renderer. Success shows a thanks page (typically you would
redirect here.
"""
form = get_form()
try:
data = form.validate(request)
except formish.FormError, e:
return self.html(request, form)
return self.thanks(request,data)
def thanks(self, request, data):
return http.see_other('/thanks')
We need to have the following in the test.html
file
<div id="formbox">
${form()|n}
</div>
The steps when this form is created are as follows
- Get a copy of the form and put it on the page
- When POST'd, validate the returned request data. If this raises an exception, errors will have been bound to the form instance.
- (On Error): Pass the form with bound errors back up the page renderer.
- (On Success): Show a thanks page.
We can also pass the success and failure callables to the validate function to simplify the form handling.
class Resource(resource.Resource):
@resource.GET()
@templating.page('page.html')
def html(self, request, form=None):
if form is None:
form = get_form()
return {'form': form}
@resource.POST()
def POST(self, request):
return get_contact_form().validate(request, self.html, self.thanks)
def thanks(self, request, data):
return http.see_other('/thanks')
If we have more than one action on a form
class Root(resource.Resource):
def get_form(self):
form = formish.Form( ('email', schemaish.String()) )
form.addAction(self.check_email_domain, 'check')
form.addAction(self.send_test_email, 'test')
return form
def check_email_domain(self, request, data):
""" Check the domain has an MX or A record """
def send_test_email(self, request, data):
""" Send a test email to this address """
@resource.GET()
@templating.page('test.html')
def html(self, request, form=None):
if form is None:
form = self.get_form()
return {'form': form}
@resource.POST()
def POST(self, request):
form = self.get_form()
return form.validate(request, self.html, form.action)
Here we have pass the form.action
method as the success callable. The whatever is in form.action
(for example, check_email_domain
) is called with (request, data)
.
If we have more than one form on a page, we can use the utility function, form_in_request
to find out which one was posted.
class Root(resource.Resource):
##
# Forms
def _email_form(self):
return formish.Form( ('email', schemaish.String()), name='email' )
def _domain_form(self):
return formish.Form( ('domain', schemaish.String()), name='domain' )
##
# Form Handling
def _POST_email(self, request):
form = self._email_form()
return form.validate(request, self.html, self.thanks)
def _POST_domain(self, request):
form = self._domain_form()
return form.validate(request, self.html, self.thanks)
##
# GET, POST, templating and thanks
@resource.GET()
def GET(self, request):
return self.html(request)
@resource.POST()
def POST(self, request):
handlers = {'email': self._POST_email, 'domain': self._POST_domain}
return handlers[formish.form_in_request(request)](request)
@templating.page('forms.html')
def html(self, request, form=None):
form_name = formish.form_in_request(request)
form = {form_name: form}
if form_name is not 'email':
form['email'] = self._email_form()
if form_name is not 'domain':
form['domain'] = self._domain_form()
return {'forms': forms}
def thanks(self, request, data):
return http.see_other('/thanks')
We could simplify this further, although I'm not sure this is quite as readable..
class Root(resource.Resource):
def form(self,name):
if name is 'email':
return formish.Form( ('email', schemaish.String()), name='email' )
if name is 'domain':
return formish.Form( ('domain', schemaish.String()), name='domain' )
@resource.GET()
def GET(self, request):
return self.html(request)
@resource.POST()
def POST(self, request):
form_name = formish.form_in_request(request)
return self.form(name).validate(request, self.html, self.thanks)
@templating.page('forms.html')
def html(self, request, form=None):
form_name = formish.form_in_request(request)
form = {form_name: form}
# Check each form, if it isn't the one passed in then fetch it.
for f in ['email','domain']:
if form_name is not f:
form[f] = self.form(f)
return {'forms': forms}
def thanks(self, request, data):
return http.see_other('/thanks')