So far, we’ve been typing
inputs into text fields. HTML forms support a handful of
input controls (what we’d call widgets in the traditional GUI world) for
collecting user inputs. Let’s look at a CGI program that shows all the
common input controls at once. As usual, we define both an HTML file to
lay out the form page and a Python CGI script to process its inputs and
generate a response. The HTML file is presented in
Example 15-11
.
Example 15-11. PP4E\Internet\Web\tutor5a.html
Read Programming Python (154 page) Page 154 Read Book Online,Top Vampire Books Read Online Free Common input devices
When rendered by a browser, the page in
Figure 15-13
appears.
Figure 15-13. Input form page generated by tutor5a.html
This page contains a simple text field as before, but it also has
radio buttons, a pull-down selection list, a set of multiple-choice
check buttons, and a multiple-line text input area. All have aname
option in the HTML file, which identifies
their selected value in the data sent from client to server. When we
fill out this form and click the Send submit button, the script in
Example 15-12
runs on the server to
process all the input data typed or selected in the form.
Example 15-12. PP4E\Internet\Web\cgi-bin\tutor5.py
#!/usr/bin/python
"""
runs on the server, reads form input, prints HTML
"""
import cgi, sys
form = cgi.FieldStorage() # parse form data
print("Content-type: text/html") # plus blank line
html = """Read Programming Python (154 page) Page 154 Read Book Online,Top Vampire Books Read Online Free Greetings
Your name is %(name)s
You wear rather %(shoesize)s shoes
Your current job: %(job)s
You program in %(language)s
You also said:
%(comment)s
"""
data = {}
for field in ('name', 'shoesize', 'job', 'language', 'comment'):
if not field in form:
data[field] = '(unknown)'
else:
if not isinstance(form[field], list):
data[field] = form[field].value
else:
values = [x.value for x in form[field]]
data[field] = ' and '.join(values)
print(html % data)
This Python script doesn’t do much; it mostly just copies form
field information into a dictionary calleddata
so that it can be easily inserted into
the triple-quoted response template string. A few of its techniques
merit explanation:
As usual, we need to check all expected fields to see
whether they really are present in the input data, using the
dictionaryin
expression. Any
or all of the input fields may be missing if they weren’t entered
on the form or appended to an explicit URL.
We’re using dictionary key references in the format string
this time—recall that%(name)s
means pull out the value for the keyname
in the data dictionary and perform
a to-string conversion on its value.
We’re also testing the type of all the expected fields’
values to see whether they arrive as a list rather than the usual
string. Values of multiple-choice input controls, like thelanguage
choice field in this
input page, are returned fromcgi
.
Field
Storage
as a
list of objects withvalue
attributes, rather than a simple
single object with avalue
.
This script copies simple field values to the dictionary
verbatim, but it uses a list comprehension to collect the value
fields of multiple-choice selections, and the stringjoin
method to construct a single string
with anand
inserted between
each selection value (e.g.,Python and
). The script’s list comprehension is equivalent to
Tcl
the callmap(lambda x: x.value,
.
form[field])
Not shown here, theFieldStorage
object’s alternative methodsgetfirst
andgetlist
can also be used to treat fields as
single and multiple items, whether they were sent that way or not (see
Python’s library manuals). And as we’ll see later, besides simple
strings and lists, a
third
type of form input
object is returned for fields that specify file uploads. To be robust,
the script should really also escape the echoed text inserted into the
HTML reply, lest it contain HTML operators; we will discuss escapes in
detail later.
When the form page is filled out and submitted, the script creates
the response
shown in
Figure 15-14
—essentially just a
formatted echo of what was sent.
Figure 15-14. Response page created by tutor5.py (1)
Suppose that you’ve written a
system like that in the prior section, and your users,
clients, and significant other start complaining that the input form is
difficult to read. Don’t worry. Because the CGI model naturally
separates the
user interface
(the HTML input page
definition) from the
processing logic
(the CGI
script), it’s completely painless to change the form’s layout. Simply
modify the HTML file; there’s no need to change the CGI code at all. For
instance,
Example 15-13
contains
a new definition of the input that uses tables a bit differently to
provide a nicer layout with borders.
Example 15-13. PP4E\Internet\Web\tutor5b.html
Read Programming Python (154 page) Page 154 Read Book Online,Top Vampire Books Read Online Free Common input devices: alternative layout
Use the same tutor5.py server side script, but change the
layout of the form itself. Notice the separation of user interface
and processing logic here; the CGI script is independent of the
HTML used to interact with the user/client.
When we visit this alternative page with a browser, we get the
interface shown in
Figure 15-15
.
Figure 15-15. Form page created by tutor5b.html
Now, before you go blind trying to detect the differences in this
and the prior HTML file, I should note that the HTML differences that
produce this page are much less important for this book than the fact
that theaction
fields in these two
pages’ forms reference identical URLs. Pressing this version’s Submit
button triggers the exact same and totally unchanged Python CGI script
again,
tutor5.py
(
Example 15-12
).
That is, scripts are completely independent of both the
transmission mode (URL query parameters of form fields) and the layout
of the user interface used to send them information. Changes in the
response page require changing the script, of course, because the HTML
of the reply page is still embedded in the CGI script. But we can change
the input page’s HTML as much as we like without affecting the
server-side Python code.
Figure 15-16
shows the response
page produced by the script this time around.
Figure 15-16. Response page created by tutor5.py (2)
In fact, this illustrates
an important point in the design of larger websites: if
we are careful to keep the HTML and script code separate, we get a
useful division of display and logic—each part can be worked on
independently, by people with different skill sets. Web page
designers, for example, can work on the display layout, while
programmers can code business logic.
Although this section’s example is fairly small, it already
benefits from this separation for the input page. In some cases, the
separation is harder to accomplish, because our example scripts embed
the HTML of reply pages. With just a little more work, though, we can
usually split the reply HTML off into separate files that can also be
developed independently of the script’s logic. Thehtml
string in
tutor5.py
(
Example 15-12
), for instance, might
be stored in a text file and loaded by the script when run.
In larger systems, tools such as server-side HTML templating
languages help make the division of display and logic even easier to
achieve. The
Python Server Pages system and frameworks such as Zope
and Django,
for instance, promote the separation of display and
logic by providing reply page description languages that are expanded
to include portions generated by separate Python program logic. In a
sense, server-side templating languages embed Python in HTML—the
opposite of CGI scripts that embed HTML in Python—and may provide a
cleaner division of labor, provided the Python code is separate
components. Search the Web for more details. Similar techniques can be
used for separation of layout and login in the GUIs we studied earlier
in this book, but they also usually require larger frameworks or
models to
achieve.