3.8 Using Forms to Receive User Input

Nearly all web applications need to accept user input. User input is captured by using forms. We will begin by demonstrating the traditional approach to handling forms, then in later sections you will see how Albatross can be used to eliminate the tedious shuffling of application values in and out of form elements.

Let's start with a program that presents a form to the user and displays to user response to the form. The sample program from this section is supplied in the samples/templates/form1 directory and can be installed in your web server cgi-bin directory by running the following commands.

cd samples/templates/form1
python install.py

The CGI program form.py is shown below.

#!/usr/bin/python
import cgi
from albatross import SimpleContext

ctx = SimpleContext('.')
ctx.locals.form = cgi.FieldStorage()

templ = ctx.load_template('form.html')
templ.to_html(ctx)

print 'Content-Type: text/html'
print
ctx.flush_content()

There are no surprises here, we are using the standard Python cgi module to capture the browser request. We want to display the contents of the request so it is placed into the execution context.

The form.html template file is used to display present a form and display the browser request.

<html>
 <head>
  <title>Display Form Input</title>
 </head>
 <body>
  Input some values to the following form and press the submit button.
  <form method="post" action="form.py">
   Text field: <input name="text"><br>
   Singleton checkbox: <input type="checkbox" name="singleton"><br>
   Checkbox group:
   <input type="checkbox" name="group" value="check1">
   <input type="checkbox" name="group" value="check2"><br>
   Radio buttons:
   <input type="radio" name="radio" value="radio1">
   <input type="radio" name="radio" value="radio2"><br>
   Option menu: <select name="select"><option>option1<option>option2<option>option3</select>
   <input type="submit" value="submit">
  </form>
  <al-include name="form-display.html">
 </body>
</html>

We have placed the form display logic in a separate template file because we wish to reuse that particularly nasty piece of template. The form display template is contained in form-display.html.

If you do not understand how the FieldStorage class from the cgi module works, do not try to understand the following template. Refer to section 3.9 which contains a small explanation of the FieldStorage class and some Python code that performs the same task as the template.

<al-for iter="f" expr="form.keys()">
 <al-exec expr="field = form[f.value()]">
 <al-if expr="type(field) is type([])">
  Field <al-value expr="f.value()"> is list:
  <al-for iter="e" expr="field">
   <al-exec expr="elem = e.value()">
   <al-if expr="e.index() > 0">, </al-if>
   <al-value expr="elem.value">
  </al-for>
 <al-else>
  Field <al-value expr="f.value()"> has a single value:
  <al-value expr="field.value">
 </al-if>
 <br>
</al-for>

You can see the program output by pointing your browser at http://www.object-craft.com.au/cgi-bin/alsamp/form1/form.py.

You will notice that each time you submit the page it comes back with all of the fields cleared again.

Typically web applications that generate HTML dynamically will hand construct <input> tags and place application values into the value attributes of the input tags. Since we are using Albatross templates we do not have the ability to construct tags on the fly without doing some very nasty tricks. Fortunately Albatross supplies some tags that we can use in place of the standard HTML <input> tags.