Previous Section Next Section

22.4 Generating HTML

Python does not come with tools to generate HTML. If you want an advanced framework for structured HTML generation, I recommend Robin Friedrich's HTMLGen 2.2 (available at http://starship.python.net/crew/friedrich/HTMLgen/html/main.html), but I do not cover the package in this book. To generate XHTML, you can also use the approaches covered in Section 23.4 in Chapter 23.

22.4.1 Embedding

If your favorite approach is to embed Python code within HTML in the manner made popular by JSP, ASP, and PHP, one possibility is to use Python Server Pages (PSP) as supported by Webware, mentioned in Chapter 20. Another package, focused more specifically on the embedding approach, is Spyce (available at http://spyce.sf.net/). For all but the simplest problems, development and maintenance are eased by separating logic and presentation issues through templating, covered in the next section. Both Webware and Spyce optionally support templating in lieu of embedding.

22.4.2 Templating

To generate HTML, the best approach is often templating. With templating, you start with a template, which is a text string (often read from a file, database, etc.) that is valid HTML, but includes markers, also known as placeholders, where dynamically generated text must be inserted. Your program generates the needed text and substitutes it into the template. In the simplest case, you can use markers of the form '%(name)s'. Bind the dynamically generated text as the value for key 'name' in some dictionary d. The Python string formatting operator %, covered in Chapter 9, now does all you need. If t is your template, t%d is a copy of the template with all values properly substituted.

22.4.3 The Cheetah Package

For advanced templating tasks, I recommend Cheetah (available at http://www.cheetahtemplate.org). Cheetah interoperates particularly well with Webware. When you have Webware installed, Cheetah's template objects are Webware servlets, so you can immediately deploy them under Webware. You can also use Cheetah in other contexts, and Spyce can also optionally use Cheetah for templating. Cheetah can process HTML templates for any purpose whatsoever. In fact, I recommend Cheetah to process templates for any kind of structured text, HTML or not.

22.4.3.1 The Cheetah templating language

In a Cheetah template, use $name or ${name} to request the insertion of the value of a variable named name. name can contain dots to request lookups of object attributes or dictionary keys. For example, $a.b.c requests insertion of the value of attribute c of attribute b of the variable named a. When b is a dictionary, this translates to the Python expression a.b['c']. If an object encountered during $ substitution is callable, Cheetah calls the object, without arguments, as a part of the lookup. This high degree of polymorphism makes authoring and maintaining Cheetah templates easier for non-developers, as it saves them the need to learn and understand these distinctions.

A Cheetah template can contain directives, which are verbs starting with # that allow comments, file inclusion, flow control (conditionals, loops, exception handling), and more. Cheetah basically provides a rich templating language on top of Python. The most frequently used verbs in simple Cheetah templates are the following (mostly similar to Python, but with $ in front of names, no trailing :, and no mandatory indents, but #end clauses instead):

#break, #continue, #pass

Like the Python statements with the same names

#echo expression

Computes a Python expression (with $ in front of names) and outputs the result

#for $ variable in $ container ... #end for

Like the Python for statement

#if ... #else if ... #else ... #end if

Like the Python if statement

#repeat $ times ... #end repeat

Repeats some text $times times

#set $ variable = expression

Assigns a value to a variable (the variable is local to this template)

#silent expression

Computes a Python expression (with $ in front of names) and hides the result

#slurp

Consumes the following newline (i.e., joins the following line onto this one)

#while $ condition ... #end while

Like the Python while statement

Note the differences between #echo, #silent, and $ substitution. #echo $a(2) inserts in the template's output the result of calling function a with an argument of 2. Without the #echo, $a(2) inserts the string form of a (calling a( ) without arguments, if a is callable) followed by the three characters '(2)'. #silent $a(2) calls a with an argument of 2 and inserts nothing in the template's output.

Cheetah has many other verbs. A Cheetah template object is a class instance and may use inheritance, override methods, and so on. However, for simple templates you will most often not need such powerful mechanisms.

22.4.3.2 The Template class

The Cheetah.Template module supplies one class.

Template

class Template(source=None,searchList=[],file=None)

Always call Template with named arguments (except, optionally, the first one); number and order of formal arguments may change in the future, but the names are guaranteed to stay. You must pass either source or file, but not both. source is a template string. file is a file-like object open for reading, or the path to a file to open for reading.

searchList is a sequence of objects to use as top-level sources for $name insertion. An instance t of class Template is implicitly appended at the end of t's search list (e.g., $a in the template inserts the value of t.a if no other object in the search list has an attribute a or an item with a key of 'a'). searchList defaults to the empty list, so, by default, t's template expansion uses only t's attributes as variables for $ substitution.

Class Template also allows other keyword arguments, but these are the most frequently used. The instance t supplies many methods, but normally you only call str(t), which returns the string form of the expanded template.

22.4.3.3 A Cheetah example

The following example uses Cheetah.Template to output HTML with dynamic content:

import Cheetah.Template
import os, time, socket

tt = Cheetah.Template.Template('''
<html><head><title>Report by $USER</title></head><body>
<h1>Report on host data</h1>
<p>Report written at $asctime:<br/>
#for $hostline in $uname
  $hostline<br/>
#end for
</p></body></html>
''', searchList=[time, os.environ])

try: tt.uname = os.uname
except AttributeError:
     tt.uname = [socket.gethostname(  )]

print tt

This example instantiates and binds to name tt a Template instance, whose source is an HTML document string with some Cheetah placeholders ($USER, $asctime, $uname) and a Cheetah #for...#end for directive. The placeholder $hostline is the loop variable in the #for statement, so therefore the template does not search the search-list objects for name 'hostline' when it expands. The example instantiates tt with a searchList argument, which sets module time and dictionary os.environ as part of the search. For names that cannot be found in objects on the search list, tt's expansion looks in instance tt itself. Therefore, the example binds attribute tt.uname, either to function os.uname (which returns a tuple of host description data, but exists only on certain platforms), if available, or else to a list whose only item is the hostname returned by function gethostname of module socket.

The last statement of the example is print tt. The print statement transforms its arguments into strings, as if str were called on each argument. Therefore, print tt expands tt. Some of the placeholders' expansions use dictionary lookup ($USER looks up os.environ['USER']); some need a function call ($asctime calls time.asctime( )); and some may behave in different ways ($uname, depending on what it finds as tt.uname, calls that attribute—if callable, as when it's os.uname—or just takes it as is, when it's already a list).

One important note applies to all templating tasks, not just to Cheetah. Templates are almost invariably not the right place for program logic to reside. Don't put more logic than strictly needed in your templates. Templating engines let you separate the task of computing results (best done in Python, outside of any template) from that of presenting the results as HTML or other kinds of structured text. Templates should deal just with presentation issues, and contain as little program logic as feasible.

    Previous Section Next Section