Since Chameleon 2.7.0 there is support for load:
TALES expression, so it is possible to load the macros template directly from another template. For details see @sverbois answer or this related question: How to use template inheritance with chameleon?
Another, older approach described in Re-usable Template Macros tutorial, involves creating a class which contains the templates which need to bre references and passing an instance of the class into the view:
class Layouts(object):
@reify
def global_macros(self):
renderer = get_renderer("templates/macros.pt")
return renderer.implementation().macros
Then you need to pass that Layouts thingie into your views. In the tutorial they did that by subsclassing the view class from Layouts
:
from layouts import Layouts
class ProjectorViews(Layouts):
...
but you could as well just instantiate it and pass it directly:
def blah(context, request):
layouts = Layouts()
return {
(whatever data you want to pass to your template)
layouts=layouts,
}
In your macros template you use metal:define-macro
to, well, define a macro:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:tal="http://xml.zope.org/namespaces/tal">
<metal:company_menu define-macro="company_menu">
<h1>Hi there!</h1>
</metal:company_menu>
</html>
To insert the macro into your other template, just use
<div metal:use-macro="view.global_macros['company_menu']"></div>
(if you use a view class subclassed from Layouts as they proposed), or
<div metal:use-macro="layout.global_macros['company_menu']"></div>
(if you instantiated the Layout object in a function-based view as I've shown in step 2 above)
Once that's working have a look at metal:define-slot
and metal:fill-slot
which will allow you to fill... err... slots in a macro with content supplied from the parent template