23.5. Generating HTMLPython 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 use the approaches covered in Chapter 24. 23.5.1. EmbeddingIf 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 the Python Server Pages (PSP) supplied by Webware (mentioned in "Webware" on page 559). Another package, focused particularly on the embedding approach, is Spyce (available at http://spyce.sf.net/). For all but the simplest problems, however, 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. 23.5.2. TemplatingTo 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'. Set the dynamically generated text as the value for key 'name' in some dictionary d. The Python string formatting operator % (covered in "String Formatting" on page 193) now does all you need: if t is your template, t%d is a copy of the template with all values properly substituted. 23.5.3. The Cheetah PackageFor advanced templating tasks, I recommend Cheetah (available at http://www.cheetahtemplate.org). Cheetah interoperates particularly well with Webware and other Python server-side web frameworks, as mentioned in "Webware" on page 559. 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 many other contexts: for example, Spyce and web.py (covered in "web.py" on page 560) can optionally use Cheetah for templating, and TurboGears (mentioned in "Other Higher-Level-of-Abstraction Frameworks" on page 559) also relies on Cheetah. Cheetah can process HTML templates for any purpose whatsoever. In fact, Cheetah is quite suitable for templating with any kind of structured text, HTML or otherwise. 23.5.3.1. The Cheetah templating languageIn 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, during the lookup. This high degree of polymorphism makes authoring and maintaining Cheetah templates easier for nondevelopers, as it saves them the need to learn and understand these distinctions. A Cheetah template can contain directives, which are verbs that start with # that allow comments, file inclusion, flow control (conditionals, loops, exception handling), and more; Cheetah provides a rich templating language on top of Python. The most frequently used verbs in simple Cheetah templates are the following (similar to Python, but with $ in front of names, no trailing :, and no mandatory indents but #end clauses instead):
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 that let you control advanced functionality such as caching, filtering, setting and deleting of variables, and method definitions. 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. 23.5.3.2. The Template classThe Cheetah.Template module supplies one class.
23.5.3.3. A Cheetah exampleThe 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 directive, so the template does not search the search-list objects for name 'hostline' when it expands. The example instantiates tt with a searchList argument, setting 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 perform 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 attributeif it is callable, as when it's os.unameor 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 in your templates more logic than is strictly needed. 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. |