In this example we’ll create a form where the user fills in his
name, date of birth, e-mail address and chooses his favorite pet.
After submitting, the user is directed either to a success page
where his name and a thank-you message are displayed or, if some of
the data is invalid or missing, to the form page again. In this
case, the form-fields are displayed with the data entered by the
user and error-messages are displayed in red beside the fields in
question.
First of all, we create a Folder in which we’ll put all the
different objects.
We then create a Page Template in this folder, called
form_display for example, which will display our
form. Enter the following code between the body tags:
<tal: define="global form here/form;
global errors request/error_messages|nothing" />
<p>Please fill in the following form:</p>
<form name="form" method="post" action="form_handle">
<table>
<tr>
<th align="left">name</th>
<td>
<tal:block content="structure python:form.user_name.render_from_request(request.REQUEST)" />
</td>
<td>
<font color="red" tal:condition="python:errors['user_name']"
tal:content="structure python:errors['user_name']"
tal:on-error="string:">
error message
</font>
</td>
</tr>
<tr>
<th align="left">date of birth</th>
<td>
<tal:block content="structure python:form.user_dateofbirth.render_from_request(request.REQUEST)" />
</td>
<td>
<font color="red" tal:condition="python:errors['user_dateofbirth']"
tal:content="structure python:errors['user_dateofbirth']"
tal:on-error="string:">
error message
</font>
</td>
</tr>
<tr>
<th align="left">e-mail address</th>
<td>
<tal:block content="structure python:form.user_email.render_from_request(request.REQUEST)" />
</td>
<td>
<font color="red" tal:condition="python:errors['user_email']"
tal:content="structure python:errors['user_email']"
tal:on-error="string:">
error message
</font>
</td>
</tr>
<tr>
<th align="left">favorite pet</th>
<td>
<tal:block content="structure python:form.user_pet.render_from_request(request.REQUEST)" />
</td>
<td>
<font color="red" tal:condition="python:errors['user_pet']"
tal:content="structure python:errors['user_pet']"
tal:on-error="string:">
error message
</font>
</td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="submit" value="submit information" /></td>
<td></td>
</tr>
</table>
</form>
At the beginning of the page we define two variables:
form and errors . The first one indicates
the path to the Formulator object that we’ll create later on; the
second one will contain a dictionary with the errors-messages or
"nothing".
The action attribute of the form tag is set to
form_handle , which is a Python script that we’ll create
later.
Then, we have a table with different rows, one row for each
form-field. A row contains an arbitrary name of the field (name,
date of birth, e-mail address and favourite pet), a form-field that
will be produced by the Formulator object (user_name ,
user_dateofbirth , user_email and
user_pet ) and an eventual error-message, which is
generated by the Formulator object as well. And of course a submit
button.
We now create our Formulator object. Add a Formulator Form to your
folder and call it form for example. In this object,
add the following fields:
- a StringField called
user_name ;
- a DateTimeField called
user_dateofbirth , check
the box which says "Display date only";
- an EmailField called
user_email ;
- a RadioField called
user_pet , enter a few pet
names in the Items field (return-key after each name) and set
the Orientation to vertical.
This Formulator object will create the different form-fields and
check them for errors. The error-messages of each field can be found
and amended under the tab Messages. You can test a field under the
tab Test.
We now create the page that will be displayed if the form has been
filled in correctly. Create a new Page Template called
form_success and paste the following code between the
body tags:
Thanks <span tal:replace="options/user">Name</span>, we appreciate your help.
This page simply displays a thank-you message containing the users
name.
We finally get to the Python script, which will handle the whole
process. Add a Script (Python) to your folder and call it
form_handle . Paste the following code in it (the
Parameter List is empty):
"""
Checks request-data against a formulator object:
- if the data is correct, a succes-page is displayed.
- if the data is incorrect, a dictionary containing the errors is added to the Request and the form page is displayed again with the original data and the error-messages.
"""
from Products.Formulator.Form import FormValidationError
request = context.REQUEST
response = request.RESPONSE
formErrors = {}
# check request-data against Formulator
try:
context.form.validate_all_to_request(request)
# request-data contains errors
except FormValidationError, e:
for i in e.errors:
title = i.field.get_value('title')
text = i.error_text
formErrors[title] = text
request.set('error_messages', formErrors)
response = context.form_display()
# request-data contains no errors
else:
# do something with the request-data here
response = context.form_success(user = request.user_name)
return response
First, this script tries to validate the request-data against our
Formulator object. If a FormValidationError is raised, which means
if a field contained invalid data or was missing data, the title of
the field in question (user_name ,
user_dateofbirth , etc) and the corresponding
error-message is added to a dictionary called
formErrors . This dictionary is then added to the
request under the name error_messages and the
form_display page is displayed again. If no
FormValidationError has been raised, which means if the form has
been filled in correctly (else statement), the
form_success page is displayed with the users name
added as an option. This is where you need to do something with the
collected data (otherwise it’s pointless having a form). For
instance, you can add the data to a database, send an e-mail or do
whatever else.
Ok, here’s how the whole thing works.
When the form_display page is displayed, the variable
errors is "nothing" since no request-object called
error_messages exists. Our Formulator object called
form produces the different form-fields, they’re empty
since no request-data exists. No error-messages are displayed since
errors is "nothing".
The user fills in the form, he makes a few mistakes. Let’s say the
date entered doesn’t exist and his e-mail address is missing. When
he pushes the submit-button, the script form_handle is
invoked. It tries to validate the request-data but a
FormValidationError is raised since the form contained errors. The
field titles and error-messages are added to the
formErrors dictionary, which is added to the request
under the name error_messages . The
form_display page is redisplayed. This time, the
dictionary formErrors is assigned to the variable
errors . The form-fields are rendered with the
request-data and if an error-message exists for a particular field,
this message is displayed in red beside the field. The user corrects
his errors and pushes the submit button again. Our Formulator object
validates the entered data, no FormValidationError is raised and the
form_success page is displayed.
Et voilà.
I hope this small tutorial was comprehensive and helpful for your
work. You can download the code of this example
here in case I made some
mistakes.
Othmar Heini |