wt module examples

Synopsis

The wt module provides an object-oriented HTML templating system. This page contains examples of how to perform various common operations using wt.

Apache Configuration

Using httpd.conf

wt uses a dual-hierarchy system to separate and identify data (HTML) files and associated code files. This requires some configuration of the web server in order to allow it to provide the correct information to wt. An example configuration for Apache using mod_rewrite is shown below:

<VirtualHost 192.168.0.1>
  ServerName www.example.com
   ...
  RewriteEngine on
  RewriteCond %{DOCUMENT_ROOT}/wt/$1.py -f
  RewriteRule ^/(.*)$ /wt/$1.py [PT,E=WT_TEMPLATE_URL:/$1,E=WT_TEMPLATE_FILENAME:%{DOCUMENT_ROOT}/$1]
  <Location /wt/>
    Action wt-handler /cgi-bin/wt.py
    SetHandler wt-handler
  </Location>
</VirtualHost>

The RewriteCond line means that the RewriteRule only takes effect if a code file corresponding to the currently-requested data file exists in the code directory hierarchy. This means that you can put ordinary static data files in the data directory hierarchy and they will be served to the user by the web server as usual without any intervention by wt.

The RewriteRule line rewrites the request URL, which originally identified the data file, to point to the code file instead. As it does this it stores information about the data file into environment variables for wt.Handler.process to retrieve later.

Finally the <Location> block uses normal Apache directives to tell the web server to execute the code files using /cgi-bin/wt.py, which is effectively the central despatch point for all wt pages within the site. The simplest possible version of this file would look as follows:

#!/usr/local/bin/python
import jon.wt as wt
import jon.cgi as cgi

cgi.CGIRequest(wt.Handler).process()

You can also perform global setup actions in this file, for example altering sys.path[0] to point to a directory where you place site-specific modules.

Using .htaccess

If you do not have access to edit httpd.conf on your web server, you can set up the server for use with wt using .htaccess files instead. The way it works and your /cgi-bin/wt.py file are exactly the same as the httpd.conf case shown above, but the mod_rewrite commands are very slightly different.

You will need two .htaccess files. The first goes in the web root directory:

RewriteEngine on
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/wt/$1.py -f
RewriteRule ^(.*)$ /wt/$1.py [E=WT_TEMPLATE_URL:/$1,E=WT_TEMPLATE_FILENAME:%{DOCUMENT_ROOT}/$1]

The second .htaccess file goes in the /wt/ subdirectory of the web root:

Action wt-handler /cgi-bin/wt.py
SetHandler wt-handler

TemplateCode examples

Simple replacements

This example simply displays the form variable foo as part of the output HTML. Note that it does not attempt to check whether or not a form variable called foo was actually passed to the server by the user's web browser, and Python will throw an exception if it wasn't. This is deliberate - if something "shouldn't happen" (e.g. if this page should never be called without a foo parameter unless the user has been inventing URLs) then just let an exception be thrown and caught by the top-level handler. If you do wish to check whether or not the parameter was passed then you can use self.req.params.has_key or self.req.params.get.

<p>The 'foo' parameter is: $$foo$$.</p>

class main(wt.TemplateCode):
  def foo(self):
    return self.req.params["foo"]

Simple sections

This example mostly demonstrates just the syntax of a section. The section name in the HTML file corresponds to a nested class name in the code file. Obviously in a real world situation the id and title would not be static but would be calculated or fetched, e.g. from a database. Note also the way that the replacement inside a URL is done using the % encoding modifier so that the replacement text has any characters that would be special to URLs encoded.

<!--wt:newsitem-->
<a href="article.html?id=$$%id$$">$$title$$</a>
<!--wt:/newsitem-->

class main(wt.TemplateCode):
  class newsitem(wt.TemplateCode):
    def id(self): return 123
    def title(self): return "this is the title"

Overriding main

This example demonstrates overriding the main method of a section. In this case it simply decides whether or not to output the contents of the section depending on whether or not a form variable show was present in the request. The section could contain replacements and sub-sections as usual, although in this simple example it contains only text.

<!--wt:section-->
...content goes here...
<!--wt:/section-->

class main(wt.TemplateCode):
  class section(wt.TemplateCode):
    def main(self, template):
      if self.req.params.has_key("show"):
        self.process(template)

Repeating sections

This example builds on the last to show how you can output a section multiple times, with different replacements each time. Again, in the real world you would presumably be fetching values from a database to display to the user.

<!--wt:section-->
<p>This is paragraph number $$num$$.</p>
<!--wt:/section-->

class main(wt.TemplateCode):
  class section(wt.TemplateCode):
    def main(self, template):
      for self.num in xrange(1, 11):
        self.process(template)

Alternating sections

This example demonstrates the selected parameter to wt.TemplateCode.process. It also demonstrates subsections, and using inheritance to share code between sections. The main section is output ten times with incrementing values of num, but different subsections are used depending on whether the number is odd or even. When self.process(template, "odd") is called, only subsections called odd are output, all other sections are ignored completely (and their associated code classes are not called).

The other interesting point about this example is that, while the HTML for the odd and even sections are different, the code is similar. We save on duplication by defining a class called subsec which odd and even then subclass. The num method is thus shared between both while the colour class variable is overridden by odd.

<!--wt:section-->
<!--wt:odd-->
<p style="border: solid $$colour$$">This is paragraph number $$num$$,
which is an odd number.</p>
<!--wt:/odd-->
<!--wt:even-->
<p style="border: solid $$colour$$">This is paragraph number $$num$$,
which is an even number.</p>
<!--wt:/even-->
<!--wt:/section-->

class main(wt.TemplateCode):
  class section(wt.TemplateCode):
    class subsec(wt.TemplateCode):
      colour = "black"
      def num(self):
        return self.outer.num
    class odd(subsec):
      colour = "blue"
    class even(subsec):
      pass
    def main(self, template):
      for self.num in xrange(1, 11):
        if self.num & 1:
          self.process(template, "odd")
        else:
          self.process(template, "even")

GlobalTemplate examples

Simple template

This example shows the simplest use of a GlobalTemplate. The first HTML file shown is placed in the template.html file in the etc directory. This HTML then does not need to be repeated for each individual page on the site, wt automatically outputs the template HTML with the individual page HTML inserted at the appropriate point. Therefore the individual page HTML files are not complete HTML files (i.e. they do not start with <html>), they are just the fragments required to complete the global template.

<html><head>
<title>Title for every page</title></head>
<body><h1>Heading for every page</h1>
<!--wt:_page/-->
</body></html>

<p>This is an individual page.</p>

class main(wt.GlobalTemplate):
  class page(wt.TemplateCode):
    pass

Overriding GlobalTemplate

This example is a bit more interesting. The global HTML template contains a dynamic replacement. In the individual page code, the template class can be used unchanged, or title can be overridden to change the template on this page. In this way you simultaneously get the benefits of shared code for the global template, and the ability to override particular properties of the template on individual pages.

<html><head>
<title>$$title$$</title></head>
<body><h1>Heading for every page</h1>
<!--wt:_page/-->
</body></html>

<p>This page is $$description$$.</p>

class template(wt.GlobalTemplate):
  title = "Default title"
  def template_name(self):
    return self.wt.etc + "/our_template.html"

class main(template):
  title = "Title for this page"
  class page(wt.TemplateCode):
    def description(self):
      return "super"

$Id$