I am using Mako for my current project and here is a problem I am
facing.
Suppose I have a file "template.html." I render this template from
Python and pass it an object "info."
Now suppose I want to factor some part of HTML in "template.html" out
to another file. Let's call this file "info.html." This file uses the
"info" variable.
I tried using the <%include file="info.html"/> in "template.html" but
I got an exception that variable "info" was not defined in
"info.html." Next I tried using the "args" argument to the <%include>
directive but I was unable to find a way to pass the object "info" via
"args" argument as it only appears to be accepting strings (note: Mako
documentation does not tell much about "args" - it's something to
improve in documentation)
Finally, I found that I can do it with namespaces, but using them does
not seem natural to me.
With namespaces I managed to wrap the contents of "info.html" in a <
%def name="display_info(info)">, and then in "template.html" I would
do the following:
<%namespace import="display_info" file="info.html"/>
And then call the newly imported "display_info" info function with
"info" object.
This does not seem natural to me, so much extra work just to get the
contents of "info.html" into my "template.html".
I wonder if there really is no way to do it with plain <%include>?
Thanks!
Peteris Krumins
www.catonmat.net
the syntax of include with args is:
<%include file="incl.html" args="x=some_expr, y=some_expr, ..."/>
the contents of "args" are evaluated in python and can be any series of
"x=y" expressions. You must put a <%page> tag in the receiving template
declaring the arguments to be received.
e.g.:
base.html:
<%
import datetime
today = datetime.datetime.now()
%>
this is base.
<%include file="incl.html" args="today=today"/>
incl.html:
<%page args="today"/>
today is: ${today}
the docs have this to say, which I'm assuming you saw - I suppose it is
expected that the contents of "args" below would be recognized as a series
of Python **kwargs:
"Include also accepts arguments which are available as <%page> arguments
in the receiving template:
<%include file="toolbar.html" args="current_section='members',
username='ed'"/>"
Hi Michael,
Thanks for explaining these points. I had missed that paragraph on <
%page args=.../>, I also was not aware that the contents of "args" are
evaluated in Python.
I played a bit more with <%include> and found an interesting behavior,
could you plase take a look:
Suppose this is the contents of "base.html":
------------[base.html]--------------
<%include file="incl.html"/>
------------[/base.html]--------------
And this is contents of "incl.html":
------------[incl.html]--------------
Hello, ${foo.name}. You are ${foo.age} old.
------------[/incl.html]--------------
And I render the template "base.html" via the following Python code:
------------[Python code]--------------
from mako.template import Template
from mako.lookup import TemplateLookup
class Foo(object):
def __init__(self):
self.name = "member"
self.age = 25
foo = Foo()
lookup = TemplateLookup(directories=['.'])
print Template(filename="base.html", lookup=lookup).render(foo=foo)
------------[/Python code]--------------
In this case variable 'foo' somehow got passed to the included
"incl.html" and the output is "Hello, member. You are 25 years old."
But now take a look the 2nd example, where the same class Foo gets
defined and instantiated inside "base2.html":
------------[base2.html]--------------
<%
class Foo(object):
def __init__(self):
self.name = "member"
self.age = 25
foo = Foo()
%>
<%include file="incl2.html"/>
------------[/base2.html]--------------
The contents of "incl2.html" is the same as that of "incl.html":
------------[incl2.html]--------------
Hello, ${foo.name}. You are ${foo.age} old.
------------[/incl2.html]--------------
Now if "base2.html" gets rendered, Mako throws an exception:
AttributeError: 'Undefined' object has no attribute 'name'.
In this case it seems "incl2.html" did not receive the variable "foo".
(In this case it receives "foo" only if I follow your original advice
on using <%page/> in incl2.html).
Could you please explain why in the first case, where 'foo' got passed
via the render() function, it acted like a super-global, but in this
case it did not?
Thanks!
Peteris Krumins
http://www.catonmat.net
>
> Now if "base2.html" gets rendered, Mako throws an exception:
> AttributeError: 'Undefined' object has no attribute 'name'.
>
> In this case it seems "incl2.html" did not receive the variable "foo".
> (In this case it receives "foo" only if I follow your original advice
> on using <%page/> in incl2.html).
>
> Could you please explain why in the first case, where 'foo' got passed
> via the render() function, it acted like a super-global, but in this
> case it did not?
your template compiles into a Python function called body(). The render() call puts all of its kwargs into the context, where they are globally accessible by all templates - when templates are compiled, Mako analyzes the variable names referenced in the body code without declaration (i.e. 'print b' as opposed to 'b=12'), and automatically declares these be pulled from the context when the body() function runs (i.e. b = context.get('b')). However variables you declare in a <% %> of your template are local to the body() def and are not accessible outside.
To achieve instant understanding into the whole thing, run:
print Template(filename="base.html", lookup=lookup).code