Writing CGI Scripts in Python

This article is neither a Python tutorial nor a CGI tutorial, but a “Python Presentation from a CGI perspective”.
Documentation and Availability
  • The Python home page is located at http://www.python.org/. On the site there is a list of mirror sites, and the current distribution of Python.

  • A tutorial and other documents including the Language Reference, Library Reference, a guide on how to extend and embed the interpreter and a FAQ can be found in the doc directory of the Python Home Page (http://www.python.org/doc/).

  • Two books will soon be available about Python:

    • Programming Python, by Mark Lutz, O'Reilly and Associates Publishers.

    • Internet Programming with Python, by Aaron Watters, Guido Van Rossum (the author of the language) and James Ahlstrom, from MIS Press/Henry Holt Publishers. See http://www.python.org/python/arwbook.html.

  • And finally, there's a newsgroup devoted to Python: comp.lang.python.

CGI Scripts

In the following text, I will assume that you run your own HTTP daemon locally. My preference is Apache, but any server will do the work, if properly configured.

And of course, you should have installed Python on your system. You'll need to configure it to use the gdbm module, since it's used in count.py.

For the examples of scripts which interface with a relational database, I've used PostGres95 (and its contributed Python module, PyGres95). PostGres95 is available from http://www.ki.net/postgres95/. PyGres95 is available from http://zen.via.ecp.fr/via_dvpt/products/pygres.html.

To understand the following text, you should know how to write an HTML page, have a general idea of how CGI works, and have a little background with C programming.

Common Scripts

Listing 3, helloworld.py, is our first script. It's very simple. Run from the command line, it will print an HTML document. But you should copy it to your cgi-bin directory, then call it from your browser with the URL http://localhost/cgi-bin/script.py.

This script displays a little message and the local time. Here, you need to note only one thing: the script must send a header describing the contents of the document. This is done by the means of the Content-type header. Common values include text/html, text/plain, image/gif or image/jpeg. The header is terminated by a blank line. It is used by the client browser, and won't appear in the generated page. And, as you'll see, the script is executed, and not just displayed in the browser. Everything printed to sys.stdout by the script will be sent to the client, while error messages will go to an error log (/usr/local/etc/httpd/logs/error_log, if you are using Apache).

Listing 4 is the well-known Count script written in Python. This is used to display a graphical counter of the number of times that a particular page has been accessed.

This script imports a module called cgi, which I'll describe later. It's used to retrieve the URL parameter passed to the script. This script interfaces with gdbm (which must be included in the modules list when Python is configured) to store { URL ; access count } couples.

This is our first introduction to Python dictionaries. A dictionary is generally referred to as an “associative array” in the literature. It means that you can access arrays by keys instead of indices. For example, if you want to handle an e-mail address book, with couples like these:

"Michel", "Michel.Vanaken@ping.be"
"Veronique", "Vero@home.sweet.home"

Here is how you should retrieve the address of Michel in C and in Python:

struct {
        char    *key ;
        char    *addr ;
} email[ MAX ] ;
int     i ;
for( i=0 ; i<MAX ; i++ ) {
  if( strcmp( email[ i ].key, "Michel" ) = 0 ) {
            printf( "%s\n", email[ i ].addr ) ;
            break ;
if( i = MAX ) {
        printf( "Not found\n" ) ;
if email.has_key( "Michel" ) :
        print email[ "Michel" ]
else :
        print "Not found"

Adding an entry with Python is also very easy :

email[ "Homer" ] =  \

adds an entry if Homer is not a valid key, and overwrites the old value if it is already present.

We see that Content-type here is image/x-bitmap (since the browser is waiting for an <img src=...>).

Of course, the bitmaps aren't very pretty (I drew them with a paint package, saved them as xbm files, then used a lot of keyboard macros and M-Kill/Yank rectangles in Emacs). The goal of this script is not to reinvent the wheel, but to allow readers to compare it with other versions widely available on the Net in different languages.

In order to use this script, the gdbm database must be created. Change the current directory to your cgi-bin directory, run Python, and type:

import gdbm
gdbm.open( "counters.gdbm", "n", 0666 )

and exit Python with Ctrl-D.

It should also be noted that the xbm file created by this script is bad. It contains an extraneous byte (added in the print_footer() function), in order to simplify the print_digit_values() function (in this version, there are no tests for commas).



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Thanks for tutorial! I found a syntax error.

Anonymous's picture

Thanks for the tutorial. :)

There is a syntax error in listing 7, in the line "if len( fields ) = 0 :". You probably see it now, it should have been "==" and not "=" - we need the comparison operator, not the assignment operator.