Below are short HOWTOs (tutorials) on how to accomplish common tasks in Cheetah. Feel free to add your own. See also the Tips section in the Cheetah Users' Guide. -- MikeOrr_ - 02 Apr 2002 --- Non-Standard Installation Process --------------------------------- The standard setup routine didn't work for me on my Win2000 system, (I haven't bothered to setup my environment to work outside of IDLE), so here is a way to manually install Cheetah into Python 2.2 (and maybe 2.1?). 1) in your \Lib\site-packages directory, create a new directory named 'Cheetah'. 2) copy everything in the distribution's 'src' directory to your new 'Cheetah' directory. 3) move all the files in the 'src' directory that are not in a subdirectory (e.g. Tools, Tests, etc.) to the 'Cheetah' directory That's it! If you now go to a Python command line, you should be able to successfully do a 'from Cheetah.Template import Template' If you care to do a further test, you can go to the 'Tests' directory under 'Cheetah' and run 'Test.py' and it should be successful. Enjoy! ViCy_ -- 30 July 2002 --- Using Tools.SiteHierarchy ------------------------- It took me a little while to manage to use this in a simple way so I thought I'd document what I did for posterity and save someone else some time. What I did was create my own MenuHierarchy.py file which inherited from Hierarchy in order to customise the output methods:: class MenuHierarchy(Hierarchy): # Add a couple of extra parameters to initialisation method _width = 0 _bgcolor = '' def __init__(self, hierarchy, currentURL, prefix='', menuCSSClass=None, crumbCSSClass=None, width=0, bgcolor=""): Hierarchy.__init__(self, hierarchy, pathToURL(currentURL), prefix, menuCSSClass, crumbCSSClass) self._currentURL = pathToURL(currentURL) self._width = width self._bgcolor = bgcolor def menuLink(self, url, text, indent): #format specific stuff here Note that I have added extra initialisation variables for the class and stored away for later use in menuLink. In my main SiteTemplate.tmpl I use the above as follows:: #attr hierarchy = [('/index.html', 'home'), ('/about.html', 'About Us'), [('/services', 'Services'), [('/services/products/index.html', 'Products'), ('/services/products/thimble.html', 'The Thimble'), ], ('/services/prices.html', 'Prices'), ], ('/contact.html', 'Contact Us'), ] #set menu = MenuHierarchy($hierarchy, $self._filePath, menuCSSClass='nav', crumbCSSClass='crumb', prefix='/', width=125, bgcolor="#CCCC99") #echo menu.menuList() The actual #set/#echo occurs wherever in the template is appropriate to create the menu bar. Notice the use of $self._filePath - I pass in the automatically created member variable, and convert it into the name of the associated .html file so it's all done automatically and there's no need to do anything in the individual template file. Anyway, hope the above is useful. -- RobertCowham_ - 12 Aug 2002 --- Another way to do a yahoo bar ----------------------------- I wanted just a simple yahoo bar on my site, not a multiline menu hierarchy. I decided to hardcode the first link ("Home") since it's on every page. In my site template I have:: #attr $crumbs = () Home #for $url, $label in $crumbs  >> ${label} #end for Any page template subclass that wants to add elements overrides $crumbs:: #attr $crumbs = [('/writings/', 'My Writings'), ('/writings/book1/', 'This Book's Title')] -- MikeOrr_ - 12 Aug 2002 -------- This recipe describes a way to implement WebwareSkins_ or, maybe better, a template selection process during runtime. It is a variation of the containment approach. -- StephanDiehl_ - 2 Nov 2002
--- Here is a Makefile that can be dropped into the root of your context, and build all of your templates with a simple 'make' command. It is also set up to clean up all generated files with a 'make clean' command. Remember to preserve tabs:: .SUFFIXES: .py .tmpl CHEETAH = cheetah CHEETAH_FLAGS = TEMPLATES := $(wildcard *.tmpl */*.tmpl */*/*.tmpl */*/*/*.tmpl) SERVLETS := $(patsubst %.tmpl, %.py, $(TEMPLATES)) PYBAK := $(patsubst %.tmpl, %.py_bak, $(TEMPLATES)) TMPLTILDE := $(patsubst %.tmpl, %.tmpl~, $(TEMPLATES)) all: $(SERVLETS) .tmpl.py: $(CHEETAH) compile $(CHEETAH_FLAGS) $< clean: rm -f $(TMPLTILDE) rm -f $(PYBAK) rm -f $(SERVLETS) rm -rf *.py~ */*.py~ */*/*.py~ */*/*/*.py~ rm -rf *.pyc */*.pyc */*/*.pyc */*/*/*.pyc -- WayneLarsen_ - 14 Feb 2002
--- Encoding with Unicode --------------------- Here is a custom filter to encode Unicode data:: import Cheetah.Filters class EncodeUnicode(Cheetah.Filters.Filter): def filter(self, val, **kw): """Encode Unicode strings, by default in UTF-8""" if kw.has_key('encoding'): encoding = kw['encoding'] else: encoding='utf8' if type(val) == type(u''): filtered = val.encode(encoding) else: filtered = str(val) return filtered import Cheetah.Template t = Cheetah.Template.Template(''' $myvar ${myvar, encoding='utf16'} ''', searchList=[{'myvar': u'Asni\xe8res'}], filter=EncodeUnicode) print t -- RenePijlman_ - 20 Nov 2003
Integration with Apache and mod_python -------------------------------------- Here is how I do it: In Apache's httpd.conf:: Options -Indexes SetHandler python-program PythonHandler cheetah PythonDebug On Order allow,deny Deny from all Order allow,deny Deny from all Here is the cheetah.py file which implements the cheetah module defined in PythonHandler:: start = "/python/" from mod_python import apache import string def handler(req): req.content_type = "text/html" module_name = string.replace (req.uri, start, "") try: exec ("""import %s tmpl = %s.%s() tmpl.req = req""" % (module_name, module_name, module_name)) except ImportError: return apache.HTTP_NOT_FOUND req.send_http_header() req.write(tmpl.respond()) return apache.OK *Warning*: no security study has been done yet, specially about the consequences of import. It now allows me to write templates like:: #silent from mod_python import apache

You are #echo self.req.get_remote_host() which displays the remote name or IP address. Using NameMapper_ is left as an exercice :-) You cannot use mod_python's Publisher (instead of my custom cheetah.py above) with most Cheetah setups. If your pages are compiled from a template, the code is in a class and the mod_python.publisher cannot find it. (If your pages are Python code, you can use http://www.modpython.org/pipermail/mod_python/2003-December/014688.html.) A better Cheetah publisher (without exec) written by Graham Dumpleton:: from mod_python import apache import os # It is assumed that Apache config or .htaccess file # blocks access to ".tmpl", ".py" and ".pyc" files. def handler(req): # Assume REST style URLs. Ie., no extension is used # for accessing Cheetah pages. On this basis, first # perform a check that there is a ".py" file in # existance. This is done because can't distinguish # between a non existant module and a module which has # a coding error in it when using the function # "apache.import_module()". By returning DECLINED, # Apache will then serve up any static files in the # directory which may otherwise be matched. target = req.filename + ".py" if not os.path.exists(target): return apache.DECLINED # Grab the module name to look for from the last part # of the path. This means that pages can be spread # across subdirectories as well. directory,module_name = os.path.split(req.filename) # Import the module. Any coding error in the module # being imported is thrown back to the user. Error # also results if by chance the target just vanished. ### module = apache.import_module(module_name,[directory]) # WRONG module = apache.import_module(module_name,path=[directory]) # Ensure that there is a class defined in the module # of the appropriate name. if not hasattr(module,module_name): return apache.DECLINED # Create instance of the class and setup request object. tmpl = getattr(module,module_name)() tmpl.req = req # Assume that HTML is being generated. req.content_type = "text/html" req.send_http_header() # Now generate the actual content and return it. req.write(tmpl.respond()) return apache.OK The above didn't work for me. ----------------------------- I use Debian Woody, and the packages they supply. Apache 1.3, Python 2.1, mod_python 2.7.8. After a lot research (I thought I'd screwed up my Apache .conf, or something like that), I started debugging, and found two problems. 1) *req.filename* had the .py extension already appended, so the script was trying *import mptest.py.py* This may have been caused by my allowing .py, .tmpl, etc. file extensions to not be blocked. But even when I left .py off the URL, it was appended by the time req.filename was passed to the script. The problem I kept getting when trying to access my template.py (not mptest.py!) was that the server was sending a MIME type of 'application/x-httpd-cgi' to the browser, but what was happening was the import of my template failed, and apache.DECLINED was getting returned. Apache was sending my script, rather the running it, in other words. 2) the call to apache.import_module() was missing the *req* parameter. Since I had mod_python 'PythonDebug On' Apache directive in place for my script dir, I then started getting tracebacks, pointing to apache.py get_config(). Looking at the source for apache.py, I noticed that import_module call was missing the 'req' parameter. I put that in, and it all started working! FWIW, I've here is an updated version of Graham's script, with doc strings added that other n00bs like me might find useful.:: """Run Cheetah .tmpl/.py files via mod_python. Provide a handler for Cheetah objects that is compatible with mod_python calling conventions. This is required, since Cheetah objects are organized in such as way as to prevent mod_python from finding the proper classes and entry points; this module remedies that situation. As an additional benefit, using this module allows Cheetah objects to be called without the .py extension, so that URLs look 'ReST'-ful. Imports: mod_python.apache - objects to interface with Apache Request, etc., objects. os - Python-supplied interface to the operating system. Exports: handler - the entry point required by mod_python for invoking an object as a request handler. Credits: This code courtesy of Graham Dumpleton and was found on the mod_python mailing list. The original version was found at http://www.modpython.org/pipermail/mod_python/2005-March/017639.html """ from mod_python import apache import os # It is assumed that Apache config or .htaccess file # blocks access to ".tmpl", ".py" and ".pyc" files. def handler(req): """Handle Apache request via mod_python. This function is the entry point required by mod_python to be implemented by Python objects that wish to handle URL requests. It searches for a file by matching the file (last) part of a URL + .py. If one is found, it tries to import it and instantiate class by the same name, then invoke the .respond() method of that class instance. (.respond() is the standard Cheetah method invoked for output of the template.) For example, URL http://www.example.com/home will cause this function to look for home.py, import it, instantiate an object of class home from it, and then invoke home.respond(), sending whatever is returned to req.write(). Required arguments: req - Apache request object. Contains information about the request, and contains the objects/methods needed to respond to the request. Side effects: output stream - writes the return value of an object's .respond() method to the output stream via req.write(). object attribute - Sets attribute req on the instantiated object to value passed as the argument to this function. content type - Looks for attribute apache_content_type in the instantiated object, and if found, sets req.content_type to that value, otherwise sets req.content_type to text/html Returns: apache.OK - requested was handled. apache.DECLINED - request not handled. Either a file by the requested name was not found, or was found but did not contain a class with same name. """ # Assume REST style URLs. Ie., no extension is used # for accessing Cheetah pages. On this basis, first # perform a check that there is a ".py" file in # existance. This is done because can't distinguish # between a non existant module and a module which has # a coding error in it when using the function # "apache.import_module()". By returning DECLINED, # Apache will then serve up any static files in the # directory which may otherwise be matched. #target = req.filename + ".py" target = req.filename if not os.path.exists(target): return apache.DECLINED # Grab the module name to look for from the last part # of the path. This means that pages can be spread # across subdirectories as well. directory,module_name = os.path.split(req.filename) # Strip off file extension prior to attempting import module_name = module_name.split('.')[0] # Import the module. Any coding error in the module # being imported is thrown back to the user. Error # also results if by chance the target just vanished. module = apache.import_module(module_name, req, [directory]) # Ensure that there is a class defined in the module # of the appropriate name. if not hasattr(module,module_name): return apache.DECLINED # Create instance of the class and setup request object. tmpl = getattr(module,module_name)() tmpl.req = req ## Assume that HTML is being generated. #req.content_type = "text/plain" #req.content_type = "text/html" # If content type not specified in tmpl, assume HTML req.content_type = hasattr(tmpl, "apache_content_type") and tmpl.apache_content_type or "text/html" req.send_http_header() # Now generate the actual content and return it. req.write(tmpl.respond()) return apache.OK Ensure MultiViews is turned off with mod_python ----------------------------------------------- There are two reasons why original code for integration of Cheetah and mod_python by Graham didn't work, however the changes made in subsequent version don't actually address them. The first problem was that the line:: module = apache.import_module(module_name,[directory]) should have been:: module = apache.import_module(module_name,path=[directory]) This has been fixed in the original code now. The subsequent poster used:: module = apache.import_module(module_name, req, [directory]) in their version but that is incorrect also. The line above where the argument supplying the directory to search is named as "path" should be used there also. The second problem wasn't in the code itself, but because the person trying to use it who had problems most likely had "MultiViews" enabled for the directory when using Apache. When using mod_python it is highly recommended that you ensure that "MultiViews" is disabled else Apache can rewrite URLs and confuse mod_python handlers:: Options -MultiViews The original code depended on "MultiViews" being disabled. And if *that* doesn't work -------------------------- Last solution, you can use Aquarium http://aquarium.sourceforge.net. -- StephaneBortzmeyer_ - 15 march 2005 The Vampire package, which is a set of glue extensions for mod_python, also includes a more developed version of the above code for integrating Cheetah into mod_python. Actual handler code for when using Vampire and Cheetah can be seen at: http://svn.dscpl.com.au/vampire/trunk/examples/cheetah/_handler.py All the code in that directory is viewable as: http://svn.dscpl.com.au/vampire/trunk/examples/cheetah/ There is also an example of session based login using Vampire and Cheetah in: http://svn.dscpl.com.au/vampire/trunk/examples/session/ The important bit managing sessions being in the "access.py" file. Vampire itself can be found at: http://www.dscpl.com.au/projects/vampire/ varyBy implemented -------------------------------------- I have implemented varyBy for #cache. It works. http://www.cherrypy.org/wiki/Cheetah -- JaroslawZabiello - 4 Jan 2005 Cheetah and Webware -------------------------------------- http://wiki.w4py.org/webwareandcheetah.html -- JaroslawZabiello - 13 Oct 2005