The wt
module provides an object-oriented
HTML templating system. This page contains examples of how to perform various
common operations using wt
.
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.
.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
examplesThis 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"]
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"
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)
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)
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
examplesThis 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
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: wt-examples.html,v 0416d65875b7 2014/03/05 17:37:06 jon $