The wt
module provides an object-oriented HTML templating
system. The design goals of the system were that it should be very simple, that
it should involve very low overhead in terms of code repeated per page, that
it should achieve as completely as possible the separation of code and data,
and that it should promote modular code re-use.
The wt
package contains the following sub-modules:
rowaccess
- class to
automatically create replacements from a dictionarytextblock
- class to assist
creation of text paragraphsThe wt
system expects you to supply two files for each page
that is to be served - an HTML file and a code file. The conventional layout
for this is to have a directory named wt
in the root of your
web tree, the directory structure inside which mirrors the structure of the
web site outside the wt
directory. For each file in the web site,
the corresponding code file is under the wt
hierarchy, with the
same name but with .py
appended. e.g. if you have an HTML file
named sales/index.html
, its code file would be named
wt/sales/index.html.py
.
The web server must be configured to pass requests through the
wt.Handler
request handler. Instructions
on how to do this with Apache are
included on the wt examples page.
Template files contain only two constructs of interest to the wt
system - replacements, and sections. Replacements are used where generated
output should be inserted, and sections are used to divide the template into
logical blocks. Each replacement corresponds to a method in a class in the
code file, and each section corresponds to a nested class.
Replacements consist of two dollar signs
followed by an identifier name (which may contain alphanumerics and underscore)
and another two dollar signs - for example, $$title$$
. You then
supply a variable or method of the same name in the current section class, the
value or return value of which will be output instead of the literal text of
the replacement. Names beinning with an underscore are reserved.
By default, the value will be passed through
cgi.html_encode
before being
output. Doing this by default simplifies programming since it is almost always
the correct option. It also means that your code is secure by default against
cross-site scripting attacks.
(You must also make sure that the browser knows what character set you are
using, but since
cgi.Request.__init__
automatically specifies the character set for you in the
Content-Type
header, you are secure by default here as well.)
To use another encoding, you can put an encoding specifier character before
the identifier name. The two alternative encodings are %
for
cgi.url_encode
(e.g.
$$%page$$
) and =
to output the return value unchanged
(e.g. $$=html$$
). Care must be taken with the literal encoding to
ensure that no unverified user input ends up being sent to the client's
browser.
Example:
<a href="article.html?id=$$%id$$">$$title$$</a>
class main(wt.TemplateCode):
def id(self): return 123
def title(self): return "this is the title"
Sections begin with an HTML comment containing only wt:
and
an identifier name (which may contain alphanumerics and underscore) - for
example, <!--wt:newsitem-->
. The section is ended by
a similar comment but with a /
before the identifier name - for
example, <!--wt:/newsitem-->
. All the data between the
start and end markers is the content of the section. Sections can be nested,
but you cannot nest a section inside another with the same name. Names
beginning with an underscore are reserved.
The code corresponding to a section is a class subclassed from
wt.TemplateCode
. An instance of the
class will be created and the section content passed to the
TemplateCode.main
. This new
instance will be used to look for methods to satisfy
replacements.
If you do not need the section to have any content, a combined
start-and-end marker in the same comment is achievable by placing a
/
character after the identifier name - e.g.,
<!--wt:_page/-->
. This is useful, for example, with
wt.GlobalTemplate
sections.
Please note that the start and end markers must appear exactly as described
- no white space is allowed at any point inside the marker.
<! --wt:invalid-->
is not valid, for example.
For example:
<!--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"
The base class for all code corresponding to template sections.
wt
A reference to the wt.Handler
instance
which is handling this request.
req
A reference to the cgi.Request
instance which contains information about this request.
outer
A reference to the TemplateCode
instance which corresponds to
the next outer-most section in the template - i.e.
an instance of the class that this class is nested within. This is
not the same thing as super
, which is the
class this class is derived from. If there is no enclosing class then
outer
is None
.
process(self, template, selected=None)
template
: string
selected
: None
, or a string, or
a sequence of strings
This method is called to process a template string. The
template
parameter contents the template to be processed. Variables
and methods to satisfy replacements and classes to
satisfy sections are looked for inside
self
.
If selected
is None
then all top-level sections in
the template string are executed. If it is a string or sequence of strings then
only top-level sections with a name matching that string or in that sequence
will be executed, and sections with other names will be ignored and no output
produced for them.
Template sections with the special name _null
are ignored. The
content of these sections is always discarded, regardless of the value of the
selected
parameter, and therefore no corresponding class is
required in the code file.
main(self, template)
template
: string
This method may be overridden by subclasses. The default implementation
simply passes the template
parameter, which is the contents of
the section which caused this object to be created,
to the process
method.
A lot of the power of the templating system is provided by overriding this
method. By redefining it you can cause the template section to be output
multiple times, or not at all, or indeed ignore the
process
method altogether and
do something entirely different with the template
parameter. You
can send output directly using the
write
method of the
self.req
variable.
Examples of the use of TemplateCode
are given in the
wt examples page.
A base class for template sections where the template
is to be fetched from another source rather than be found in-line in the HTML
file. The normal HTML contents of any section derived from
GlobalTemplate
are temporarily suspended and used for a
subsection named page
instead.
A separate file is read to provide the HTML template for the
GlobalTemplate
section.
Examples of the use of GlobalTemplate
are given in the
wt examples page.
page
This variable may be overridden by subclasses. A
TemplateCode
subclass which is
called with the original template contents that would otherwise have been used
for the GlobalTemplate
class. The default value is
TemplateCode
. Due to the extra
processing which GlobalTemplate
interposes, the corresponding
HTML template section to this class should be named _page
, not
page
.
template_name(self)
Returns: a string
This method may be overridden by subclasses. This method returns the filename
to read to fetch the template contents for this section. The default
implementation returns
self.wt.etc + "/template.html"
.
This Handler
class should be called to process a request
using the wt
templating system. The default implementation uses
various environment variables which will have been set up by the
Apache configuration shown on the
wt examples page to determine the code
and template names, but various methods are provided which may be overridden to
make these choices in a different way (for example, if you are using a different
web server). All wt.TemplateCode
objects receive a reference to the current instance in their
self.wt
instance variable.
req
A reference to the cgi.Request
instance which contains information about this request.
etc
The directory DOCUMENT_ROOT + "../etc"
. This is used as a
default location by
GlobalTemplate.template_name
to locate templates. It is also a useful location to place miscellaneous files
associated with a web site that should not be under the
DOCUMENT_ROOT
.
template
The full pathname of the template file.
get_template_encoding(self)
This method may be overridden by subclasses. It returns the character
encoding used for the template file, or None
if no encoding
conversion is to be done. If it is not None
then the template
file will be assumed to be using the specified character encoding and the
template
parameter to
TemplateCode.main
will be
a unicode
string instead of a normal string. The default
implementation returns None
.
pre_load(self)
This method may be overridden by subclasses. Its default implementation does
nothing. It is called before the template is located or the page code loaded.
self.req
and
self.etc
are available.
pre_request(self, obj)
obj
:
wt.TemplateCode
instance
This method may be overridden by subclasses. Its default implementation does
nothing. It is called just before
obj.main()
is called to process
the request. All the instance variables of self
have already been
set up.
post_request(self, obj)
obj
:
wt.TemplateCode
instance
This method may be overridden by subclasses. Its default implementation does
nothing. It is called just after
obj.main()
has handled the
request.
process(self, req)
req
:
cgi.Request
instance
This method may be overridden by subclasses. It calls
self._get_template()
,
self._get_code()
and
self._get_etc()
to determine
the various files and directories to use when handling the request. The code
file should contain a subclass of
wt.TemplateCode
named
main
, which is passed the entire template file. The global
namespace the code file is executed in is initialised to contain a reference
to the wt
module in the variable wt
, thus avoiding
the need to do import jon.wt as wt
in every code file. See the
wt examples page for how to set up
Apache so that wt
knows
what's going on.
You can add code to run before and/or after every request by overriding
this method and performing processing before and/or after calling the
base wt.Handler.process
base method.
Example:
class Handler(wt.Handler):
def process(self, req):
self.session = session.Session(req, url=0)
wt.Handler.process(self, req)
self.session.save()
fcgi.Request({fcgi.FCGI_RESPONDER: Handler}).run()
_get_template(self)
Returns: string
This method may be overridden by subclasses. It returns the full pathname of
the template file to be used for this request.
self.req
has already been set up. The
default implementation looks for an environment variable whose name matches
(REDIRECT_){0,4}WT_TEMPLATE_FILENAME
.
_get_code(self)
Returns: string
This method may be overridden by subclasses. It returns the full pathname of
the code file to be used for this request.
self.req
and
self.template
have already been
set up. The default implementation returns the environment variable
PATH_TRANSLATED
.
_get_etc(self)
Returns: string
This method may be overridden by subclasses. It returns the full pathname of
the directory which self.etc
will be
set to. self.req
has already been set
up. The pathname should not end with a /
character. The default
implementation returns the equivalent of DOCUMENT_ROOT/../etc
.
This class is identical to Handler
,
except that it uses
cgi.DebugHandlerMixIn
so
that if an exception is thrown by a template page then a traceback will be
sent to the browser. This class may be used during development to aid debugging
but should never be used in a production environment since it will leak private
information to the browser.
$Id: wt.html,v 0416d65875b7 2014/03/05 17:37:06 jon $