[mod_python] Building a web application using Cheetah and mod_python

Graham Dumpleton grahamd at dscpl.com.au
Fri Oct 27 23:32:35 EDT 2006


On 28/10/2006, at 7:44 AM, Sebastian Celis wrote:

> Hello,
>
> I am new to this list and have just recently begun to work on a
> project where I wish to use mod_python.publisher and cheetah to drive
> an entire web application.  I apologize if the following topics have
> been discussed to death recently, but I have read through the
> documentation on both sites and have searched through the mailing-list
> archives and while I have seen similar discussions, I have yet to find
> definitive answers.  I am able to get most things to work, however I
> can't help but feel that there are better ways of approaching some of
> my situations.
>
> First, I'll quickly describe my directory structure:
>
> /var/www/app -- The base directory to the web application.  This will
> directly contain most of the python files that correspond directly to
> URLs.  For example, index.py, login.py, etc.  In this directory.
> /var/www/app/templates -- Contains all of my cheetah templates.
> /var/www/app/include -- Contains the python utility modules I am
> writing specifically for this application.
>
> Now, onto the questions.
>
>
> 1) Importing compiled cheetah templates
>
> Assume I have code like the following in /var/www/app/test1.py
>
> ######################################
> from mod_python import apache
> from Cheetah.Template import Template
>
> def index(req):
>    req.content_type = "text/html"
>
>    dict = {'title': 'My Title!', 'message': 'Hello world!'}
>    templateModule = apache.import_module("templates/myTemplate")

Using '/' in the module name like this is not portable and is dependent
on peculiarities of the behaviour of Python on a specific platform.  
It will
not for example work on Mac OS X and also possibly not on Windows.

>    t = getattr(templateModule, "myTemplate")()
>    searchList = t.searchList()
>    searchList.insert(0, dict)
>
>    return(t.respond())
> ######################################
>
> Is this the best way to import template modules and then evaluate  
> them?

No, in as much as you are having to create a parallel hierarchy of  
publisher
handlers for each Cheetah page. You would be better off using a custom
handler which does the dispatch direct to the compiled Cheetah template
classes. See the mod_python handler described in:

   http://wiki.cheetahtemplate.org/cheetah-recipes.html

> 2) Modifying PythonPath prevents modules from being imported
>
> Inside file /var/www/app/test2.py, I have the following code:
>
> import config
> (or)
> config = apache.import_module("config")
>
> Both of these commands load /var/www/app/config.py, and seem to work
> fine.  However, if I add
>
> PythonPath "['/var/www/app/templates']+sys.path"
>
> to my apache configuration, I get an error next time I run test2.py.
>
> ###
> Mod_python error: "PythonHandler mod_python.publisher"
>
> Traceback (most recent call last):
>
>  File "/usr/lib/python2.4/site-packages/mod_python/apache.py", line
> 299, in HandlerDispatch
>    result = object(req)
>
>  File "/usr/lib/python2.4/site-packages/mod_python/publisher.py",
> line 213, in handler
>    published = publish_object(req, object)
>
>  File "/usr/lib/python2.4/site-packages/mod_python/publisher.py",
> line 412, in publish_object
>    return publish_object(req,util.apply_fs_data(object, req.form,  
> req=req))
>
>  File "/usr/lib/python2.4/site-packages/mod_python/util.py", line
> 439, in apply_fs_data
>    return object(**args)
>
>  File "/var/www/app/test2.py", line 8, in index
>    config = apache.import_module("config")
>
>  File "/usr/lib/python2.4/site-packages/mod_python/apache.py", line
> 461, in import_module
>    f, p, d = imp.find_module(parts[i], path)
>
> ImportError: No module named config
> ###
>
> Why does this initially work but then stop working once I add a
> directory to my path?  I can fix it by adding '/var/www/app' to my
> PythonPath as well, but I don't understand why it didn't work before
> that.

That is just how mod_python has always worked. Setting PythonPath
stops mod_python looking in the directory the handler was specified
for. Yes it is a pain. FWIW, this behaviour changes in mod_python 3.3
where the whole issue of module importing is dealt with a bit  
differently
and is much more consistent and predictable.

Current versions of mod_python have a lot of issues when it comes
to the module importer. You should really have a read of:

   http://www.dscpl.com.au/wiki/ModPython/Articles/ 
ModuleImportingIsBroken

> 3) Cheetah and #include
>
> I have read a lot about why mod_python sets the current working
> directory to '/', but this seems to be causing some larger problems
> when cheetah comes into play.  (3) and (4) discuss two issues that I
> am having trouble with.
>
> Here is /var/www/app/templates/testPage.tmpl:
> ###
> #include 'header_include.tmpl'
> <head>
> <title>$title</title>
> </head>
> <body>
> <p>$message</p>
> </body>
> #include 'footer_include.tmpl'
> ###
>
> However, as this actually tries to load /header_include.tmpl and
> /footer_include.tmpl instead of the ones located in my templates
> directory, this will not work.

If you are going to use compiled templates, you are possibly better  
off using
a site page base class and have specific pages extend that page. These
common blocks are then accessible through the base class. This means you
get the benefit of compiled code for the included blocks as well,  
instead of
it having to be interpreted each time.

> I came up with two workarounds,
> however I don't really love either:
>
> a)
>
> ###
> #include os.path.join(os.path.dirname(__file__),  
> 'header_include.tmpl')
> <head>
> <title>$title</title>
> </head>
> <body>
> <p>$message</p>
> </body>
> #include os.path.join(os.path.dirname(__file__),  
> 'footer_include.tmpl')
> ###
>
> b)
>
> Actually pass $templatesDir into all of my templates and then  
> instead call:
>
> ###
> #include os.path.join(templatesDir, 'header_include.tmpl')
> <head>
> <title>$title</title>
> </head>
> <body>
> <p>$message</p>
> </body>
> #include os.path.join(templatesDir, 'footer_include.tmpl')
> ###
>
> I guess I'm leaning toward (a), but both seem cumbersome and slower
> than necessary.  Is there a better way to do this?

If my memory of Cheetah is correct, then extending from a site page  
which
has reusable bits like this as I describe above is better.

> 4) Cheetah and inheritance
>
> Assume these two files:
>
> /var/www/app/templates/overall_base.tmpl
> ###
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
>          "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
> <head>
>    <title>$title</title>
> </head>
> <body>
>    $bodyContent
> </body>
> </html>
> ###
>
> /var/www/app/templates/overall_base_extender.tmpl
> ###
> #overall_base = apache.import_module("overall_base")
> (or)
> #from overall_base import overall_base
>
> #extends overall_base
> #def title
> Welcome to Foo
> #end def
> #def bodyContent
> Hello world!
> #end def
>
> This second file only works if I add /var/www/app/templates to my
> PythonPath.  And, due to (2) above, I then also have to add
> /var/www/app to PythonPath.  Is this really necessary?=

With the version of mod_python you are using, yes it is necessary.

> #overall_base = apache.import_module("overall_base",
> path=[os.path.dirname(__file__)])
>
> doesn't seem to work inside the cheetah template file.  Even
>
> #sys.path.append(os.path.dirname(__file__))
> #overall_base = apache.import_module("overall_base")

That one I am not sure about. You may be hitting one of the other  
problems
with PythonPath based module importing which is you can't easily have  
the
same name module in different directories and be sure you import the one
you want.

In general I wouldn't recommend using apache.import_module() within
Cheetah templates explicitly.

> doesn't seem to work.  Is there any way to get inheriting templates to
> work without modifying PythonPath to include all the directories where
> my base templates might be located?

Not really.

> I apologize for the huge length of this e-mail.  I am still fairly new
> to mod_python and cheetah, but so far I really like what I see.  I
> just feel like there are a few issues I need to wrap my head around
> before I can really dive into developing applications.  Any pointers
> or help with these issues that you can provide would be greatly
> appreciated.

Things are a bit easier to manage and easier to predict when  
mod_python 3.3
can be used. Version 3.3 of mod_python hasn't been released yet, but  
is quite
close. If you want to try the source for mod_python out of the  
Subversion
repository, then can suggest better ways of doing things.

Graham


More information about the Mod_python mailing list