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.
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.
|