Hi Ryan,
I've been using mako recently for its feature set and caching
abilities so wanted to integrate it into the new web.py v0.3. This is
what I came up with based on Anands example. It's fairly well tested
against the latest webpy.dev branch.
Add to the bottom of web/template.py (or refactor to your pleasing):
class render_mako:
"""
A web.py-ish interface to the Mako templating engine.
See http://webpy.org/, http://makotemplates.org/
"""
def __init__(self, path='.', ext='.html', compile_path=None,
_lookup=None):
"""
Create a new mako template renderer.
Example:
render = web.template.render_mako('templates/')
render.something(var='value')
Common usage:
web.render = web.template.render_mako('templates/')
Parameters:
path: The directory in which to look for templates. (default:
'.')
ext: Extension to add to template files. (default: '.html')
compile_path: Compile templates to specified directory.
(default: None = no caching)
"""
import mako.template, mako.lookup
# Enable rendering mako template objects by calling
mako.template.Template.__call__ =
mako.template.Template.render
self.path = path
self.ext = ext
if _lookup is None:
_lookup = mako.lookup.TemplateLookup(
directories=[path],
module_directory=compile_path)
self._lookup = _lookup
def __str__(self):
return repr(self)
def __repr__(self):
return '<web.template.render_mako path=\'%(path)s\' ext=\'%
(ext)s\'>' % self.__dict__
def __getattr__(self, name):
"""
Tries to return a template of the given attribute name, or a
new
render object rooted in the attribute named directory, or
throws
a KeyError.
"""
import os.path
template = os.path.join(
self.path[len(self._lookup.directories[0]):],
name + self.ext)
path = os.path.join(self.path, name)
if self._lookup.has_template(template):
return self._lookup.get_template(template)
elif os.path.isdir(path):
return render_mako(path, ext=self.ext,
_lookup=self._lookup)
else:
raise KeyError("Template or directory '%s' does not
exist." % name)
A little example (not thoroughly tested):
hello.py:
import web
web.render = web.template.render_mako(
path='docs/', compile_path='var/cache/templates')
urls = (
'/(.*)?', 'hello',
)
class queue:
def GET(self, name=None):
web.header('Content-Type', 'text/html')
if name != None:
return web.render.hello.name(locals())
else:
return web.render.hello.noname()
def hello_app():
return web.application(urls, globals())
docs/layout.html:
<html><head><title>Hello Example</title></head><body>${next.body()}</
body></html>
docs/hello/name.html:
<%inherit file="/layout.html"/>
Hi ${name}!
docs/hello/noname.html:
<%inherit file="/layout.html"/>
Hello!
I also use a small start-up script to make reloading work:
start.py:
import web
from hello import hello_app
if __name__ == "__main__":
import sys
middleware = []
app = hello_app()
if '--debug' in sys.argv:
sys.argv.remove('--debug')
middleware.append(web.reloader)
app.internalerror = web.debugerror
app.run(*middleware)
using `./start.py --debug` helps.
TODO:
- Maybe using the render_mako method should automatically include the
Content-Type header?
- I can see this turning into a templating API. :-D
Regards,
Samuel Cochran
On Sep 3, 3:05 am, "Ryan Tracey" <[EMAIL PROTECTED]> wrote:
> On 31/08/07, Ryan Tracey <[EMAIL PROTECTED]> wrote:
>
>
>
> > On 31/08/2007, Anand <[EMAIL PROTECTED]> wrote:
>
> > > > from mako.lookup import TemplateLookup
> > > > mylookup = TemplateLookup(directories=['templates/'],
> > > > module_directory='mako_modules')
>
> > > > def serve_template(templatename, **kwargs):
> > > > mytemplate = mylookup.get_template(templatename)
> > > > print mytemplate.render(**kwargs)
>
> > > I think templator approach is the best.
>
> > I have no preferences as yet. Just in the process of converting a
> > web.py 0.1 app into a web.py 0.2 app and hit some snags with templator
> > -- probably just my own conditioning that needs to change ;-)
>
> > Do you reckon there'll be a performance hit associated with using a
> > third-party templating system?
>
> > > from mako.lookup import TemplateLookup
>
> > > class mako_render:
> > > def __init__(path):
> > > self._lookup = TemplateLookup(directories=[path],
> > > module_directory='mako_modules')
>
> > > def __getattr__(self, name):
> > > path = name + '.html'
> > > t = self._lookup.get_template(path)
> > > t.__call__ = t.render
> > > return t
>
> > > render = mako_render('templates/')
>
> > > class hello:
> > > def GET(self, name):
> > > i = web.input(times=1)
> > > if not name:
> > > name = 'world'
> > > print render.hello(name=name, times=int(i.times))
>
> > Thanks very much Anand, I'll give this a try.
>
> Hi Anand
>
> I tried out the method you suggested but had to make a few changes get
> it to work (in my environment?) For instance, despite the "t.__call__
> = t.render" in __getattr__ I cannot call render.hello(...). I can, as
> expected, call render.hello.__call__(...). I got around this by having
> __getattr__ return t.render instead of just t. Also, to get around the
> problem of web.py wrapping the template's output in <pre> tags I call
> web.header(...) before I call render.hello(...). Here is what I am
> doing:
>
> from mako.lookup import TemplateLookup
> class mako_render:
> def __init__(self, path):
> self._lookup = TemplateLookup(directories=[path],
> module_directory='mako_modules')
> def __getattr__(self, name):
> path = name + '.html'
> t = self._lookup.get_template(path)
> #t.__call__ = t.render
> return t.render
>
> render = mako_render('templates/')
>
> class hello:
> def GET(self, name):
> i = web.input(times=1)
> if not name:
> name = 'world'
> web.header("Content-Type", "text/html; charset=utf-8")
> print render.hello(name=name, times=int(i.times))
>
> Can you see any way I could get around having to use the web.header
> method? By returning the method (t.render) and not the object (t) am I
> necessitating the use of web.header? I dunno, my OO knowledge is very
> poor, for instance I was blown away by __gettr__ and had to contrive a
> simple case to understand it. Don't laugh:
>
> In [7]: class Foo:
> ...: def __init__(self, action):
> ...: self.action = action
> ...: def __getattr__(self, thing):
> ...: return thing +' '+ self.action
> ...:
>
> In [8]: f = Foo('barks')
>
> In [9]: f.dog
> Out[9]: 'dog barks'
>
> Thanks again for the suggestion -- I now know a bit more than I did on Friday!
>
> Cheers,
> Ryan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"web.py" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/webpy?hl=en
-~----------~----~----~----~------~----~------~--~---