Dear Sam,
here is a copy of my cheetahPages file to look at. To use it in a
servlet I usually write my servlets like this:
from cheetahPages import cheetahPage
class servlet(cheetahPage):
def writeTemplate(self):
self.write(self.cheetahTemplate('template.html').render())
My cheetahPages files does a couple of things for me. First it creates
a cheetahTemplate object which takes care pasisng the correct
searchList to the template, which is usually passed to render as an
argument. The cheetahPage class does all the real work. It takes a
template (which can be named anything you want, I always use .html
instead of the conventional .tmpl because Dreamweaver deals with it
easier) and compiles the template into a compiled template and loads
the template. If the template is already compiled, it checks the date
of the compiled template against template file and recompiles if needed
(this is a little weak, because my original code, commented out, was
compiling too often), and reloads the compiled template if needed.
Like I said this is only one way to use cheetah, but it really works
well for me. You'll notice the templateRoot function. This returns
the relative location of the templates folder (assumed to be the same
as the servlet if it si not overwritten). If templateRoot is present
it looks there for the template files, this helps keep all my templates
in one nice little package again separate from my servlets. Hope this
helps.
Jose
> -------- Original Message --------
> Subject: Re: [Webware-discuss] several questions about webware
> From: "Sam Nilsson" <[EMAIL PROTECTED]>
> Date: Mon, January 31, 2005 12:24 am
> To: "jose" <[EMAIL PROTECTED]>
>
> jose wrote:
> > I find that this keeps my presentation code
> > nicely separated from my program code, and keeps the templates very clean.
> > I would be happy to share my cheetahPage with anyone if there is interest.
> >
> > Jose
>
> Hi Jose,
>
> I would appreciate taking a look at your cheetahPage!
>
> - Sam Nilsson
from WebKit.Page import Page
from Cheetah.CheetahWrapper import CheetahWrapper
import os, re, time
__Version__ = 1.1
__Author__ = 'Jose Galvez, MD'
class cheetahTemplate:
'''
Cheetah Template object
The purpose of this class to represent a cheetah template. Once the
template is created the object has a single method, render which takes
as an optional argument the searchList and returns the rendered html
This class it very tightly inigrated with cheetahPage
@author: Jose Galvez
'''
def __init__(self, base, mod):
'''
cheetahTemplate constructor
@param base: The parent or base object, used as the base searchList
@param mod: The compiled cheetah module as returned by cheetahPage._loadTemplate
'''
self.base = base
self.modName = mod.__name__.split('.').pop()
self.mod = getattr(mod, self.modName)
def render(self, searchList=False):
'''
The only exposed method that a template may have
@param searchList: Optional paramiter, the searchList is used by cheetah
to find varaibles for substitution
@return: rendered html as string
'''
tmpl = self.mod()
# now deal with the search list
# did we supply a search list? if so deal with it, if not pass
# an empty one
if not searchList:
searchList = []
else:
if type(searchList) == tuple:
searchList = list(searchList)
elif type(searchList) == dict:
searchList = [searchList]
elif type(searchList) == str:
raise 'Can not pass a string as a searchList, try using Vars() to accomplish this'
searchList.append(self.base)
# searchList manipulation to move the various parts around
# so that they are searched in the correct order
# dump original searchList into a holding pen using pop to emply
# out the searchList
orgSl = []
for i in range(len(tmpl.searchList())):
orgSl.append(tmpl.searchList().pop(0))
# add our own stuff the searchList
tmpl.searchList().extend(searchList)
# add the original searchList to the end of the list
tmpl.searchList().extend(orgSl)
# end searchList manipulation
#return the compiled template
return tmpl.respond()
class cheetahPage(Page):
'''
site page for cheetah templates
1. compileTemplate(string)
compile the template if it has changed since the last time
it was compiled and return a cheetahTemplate object
2. Important to note that basetemplates are not reloaded very
effeciantly, this is a limitation of webware not cheetah
'''
def __init__(self):
Page.__init__(self)
# Init the cheetah cache object
self.dependancyCheck = re.compile('#from (.*) import (?P<dependancy>.*)')
self.cheetahCache = {}
self.reloadList = []
def _respond(self, transaction):
"""
Handles actions if an _action_ field is defined, otherwise
invokes writeHTML().
Invoked by both respondToGet() and respondToPost().
"""
req = transaction.request()
# Check for actions
for action in self.actions():
# note the added new action do_ taken form java stuff
if ((req.queryString().find('do_%s' % action) != -1) or
(req.queryString().find('action_%s' % action) != -1) or
(req.queryString().find('_action_%s' % action) != -1)):
if self._actionSet().has_key(action):
self.handleAction(action)
return
elif req.hasField('do_%s' % action):
if self._actionSet().has_key(action):
self.handleAction(action)
return
elif req.hasField('_action_%s' % action) or \
req.field('_action_', None) == action or \
(req.hasField('_action_%s.x' % action) and \
req.hasField('_action_%s.y' % action)):
if self._actionSet().has_key(action):
self.handleAction(action)
return
self.writeHTML()
def hr(self, length = 90):
'''
writes a line on a web page set at 90%
xhtml complient now
'''
self.writeln('<hr width="%s" />' % (str(length) + '%',))
def br(self):
'''
writes a <BR> tag
xhtml complient now
'''
self.writeln('<BR />')
def preAction(self, actionName):
'''
preAction is not needed any longer
'''
pass
def postAction(self, actionName):
'''
postAction is not needed any longer
'''
pass
def writeHTML(self):
'''
divert the writeHTML from writeContent to writeTemplate
my personal choice this can easily be changed back to
something else or removed entilry
'''
self.writeTemplate()
def writeTemplate(self):
'''
default page content, this methode needs to be overwritten
to produce the default page content
'''
self.writeln('Sorry this page does not have any default Content')
def templateRoot(self):
'''
Defines the template root for a site if you need to
this is generally done best in a "site.py" page for
general importation
If not overwritten it will be assumed that the template root
is at the same level as the servlet.
Return string template root, this should be either a relative location to
the servlets, or an absolute location
'''
return 0
def cheetahTemplate(self, template, g=False):
'''
1. compiles a tempalte and returns a compiled template object
2. optionally provide the global namespace otherwise an error will
be generated
'''
self._compileTemplate(template)
modName = os.path.splitext(template)[0]
mod = self._loadTemplate(modName, g=g)
chT = cheetahTemplate(self, mod)
return chT
def _loadTemplate(self, template, g=False):
'''
Loads a given module as well as handeling whether the template
modules needs to be reloaded
@param tempalte: name of the compiled template
@type template: string
@parm g: globals - Globals must be passed to the function to ensure that the
template is loaded into the correct namespace
@type g: globals dict
'''
if not g:
# lets try to make up my own globals variable, this might break in
# the next version of python, if so I'll have to figure something else out
try:
g = {'__name__':self.__module__}
except:
raise 'You must pass globals() to the loadTemplate function for it to work'
if self.templateRoot():
mod = __import__(self.templateRoot()+'.'+template, g, {}, [template])
else:
mod = __import__(template, g, {}, [template])
self._reloadTemplate(mod)
return mod
def _templatePath(self, t):
'''
internal method used by template to get and deal with
template root paths
uses templateRoot to define template locations if defined
@param t: template file
@type: string
@return: fullTemplatePath - full path to template file
@return: templateName - name of compiled template
'''
# First get cheetah root
if self.templateRoot():
# Template paths must be relative to the servlet
# using them otherwise return an error
# first lets figure out what the real location of the template root is
chRoot = self.serverSidePath(self.templateRoot())
if not os.path.exists(chRoot):
# the relative path does not exsist
raise 'Sorry the path %s does not exsist' % chRoot
fullTemplatePath = os.path.join(chRoot, t)
else:
fullTemplatePath = self.serverSidePath(t)
templateName, templateExt = os.path.splitext(t)
return fullTemplatePath, templateName, templateExt[1:]
def _reloadTemplate(self, mod):
'''
reloads a compiled template if it marked for reloading
'''
reload(mod)
modName = mod.__name__.split('.').pop()
if modName in self.reloadList:
self.reloadList.remove(modName)
reload(mod)
def _compileTemplate(self, t):
'''
compiles the given template into a compiled template
Only compiles template if it has changed otherise it leaves it along
@param t: template
@type t: string
'''
# compile only if we need too
fullTemplatePath, templateName, templateExt = self._templatePath(t)
fullCompiledTemplatePath = os.path.splitext(fullTemplatePath)[0]+'.py'
mtime = os.path.getmtime(fullTemplatePath)
cachedMtime = self.cheetahCache.get(templateName, False)
fullCompiledTemplatePathExists = os.path.exists(fullCompiledTemplatePath)
if ((fullCompiledTemplatePathExists) and (not cachedMtime) and (not self.application().server().config()['AutoReload'])):
# if the compiled template exsits and we just don't have a record of it in our
# cheetahCache, then don't worry assuming AutoReload is set to 0, just add it, this assums that the compiled
# tempalte is actaully the correct one, if this is not correct delete it
# and let the system rebuild it form scratch
self.cheetahCache[templateName] = mtime
elif ((mtime != cachedMtime) or (not fullCompiledTemplatePathExists)):
# check to make sure __init__ exsists
if not os.path.exists(os.path.join(os.path.dirname(fullTemplatePath), '__init__.py')):
initFile = file(os.path.join(os.path.dirname(fullTemplatePath), '__init__.py'), 'w')
initFile.write('# __init__ #')
initFile.close()
# open template and see if there any any dependancies that we need to compile first
tmpl = file(fullTemplatePath)
tLn = tmpl.readline()
while tLn[0] == '#': # for l in range(10): #read only first 10 line
#tLn = tmpl.readline()
dependanceCheck = self.dependancyCheck.match(tLn)
if dependanceCheck:
dependancy = dependanceCheck.groupdict().get('dependancy', False)
if dependancy:
# we may be loading something that we don't have to compile
try:
self._compileTemplate(dependancy+'.'+templateExt)
except:
# nothing to do I just don't want an error to be raised
pass
tLn = tmpl.readline()
tmpl.close()
# insert the mtime into the template cache
self.cheetahCache[templateName] = mtime
# insert the template in to the reload variable
self.reloadList.append(templateName)
baseTemplateDir = os.path.dirname(fullTemplatePath)
cheetahOptions = ['cheetahPage',
'compile',
'--idir', baseTemplateDir,
'--odir', baseTemplateDir,
'--iext', templateExt,
'--nobackup',
templateName]
# actually compile the template
CheetahWrapper().main(cheetahOptions)