Chameleon macro examples

430 views
Skip to first unread message

Mike Orr

unread,
May 3, 2013, 6:48:50 PM5/3/13
to pylons-...@googlegroups.com
Are there any good examples around of using Chameleon with a site template macro? I normally make my sites by inheriting from a Mako template that provides a standard <head> and header/footer, with the page template overriding the title, possibly adding stylesheet and Javascript links, supplying data for the breadcrumbs, etc. I know this can be done with Chameleon macros and slots and providing the site template in the template namespace, but does anyone have an example of it that I can borrow the syntax? Kotti does this but it also has a custom 'api' object in the template namespace, which I'm not sure if I want to follow.

--
Mike Orr <slugg...@gmail.com>

Mike Orr

unread,
May 3, 2013, 6:50:55 PM5/3/13
to pylons-...@googlegroups.com

Also, is there a way to make Chameleon put its compiled templates in a different directory from the source? On my server the source directory will be read-only at runtime. Or is there a command to precompile all templates in one step?

Mike Orr

unread,
May 3, 2013, 7:20:16 PM5/3/13
to pylons-...@googlegroups.com
Or maybe I should just ask, what are the remaining things you can do in Chameleon that you can't do in Mako? I'm interested in the well-formed XML guarantee and Pyramid's Chameleon internationalization support. But on the other hand the Chameleon syntax is so different it's a large learning curve, especially to port inheritance relationships and def's the like. And shoehorning variable assignments and such into tag attributes does look the hyperbole of screwy sometimes, even though I like the idea of if'ing a tag rather than an arbitrary block.

Has Pyramid/Mako's internationalization caught up with Chameleon yet? Should I just give up on XML pre-validation and validate the rendered pages?  Am I missing anything else besides not using Chameleon. (Anything in the sense of capabilities, not syntax or speed.)

--
Mike Orr <slugg...@gmail.com>

Jonathan Vanasco

unread,
May 3, 2013, 9:32:24 PM5/3/13
to pylons-...@googlegroups.com
Have you looked at Jinja2 ?  You can customize the escape characters so that it nearly looks like Mako (or Moustache).  Not sure if it suits your other needs, but it has pretty decent template inheritance and macros.

I'm prototyping some 'user editable templates' with Jinja2 and the sandbox mode.  So far it seems pretty good.

bismigalis

unread,
May 4, 2013, 3:06:25 AM5/4/13
to pylons-...@googlegroups.com
I like Chameleon. But I dont like doing layout through macros. So I started using "wrapper" feature of Pyramid. You just do "layout" view.
Then in view_config you specify wrapper="my_layout_view". Now in your view template there is not any mention of layout, it is just template. And now layout has it's own template(it even can be another template lang). In your_layout_view you return {'content':request.wrapped_response.unicode_body}, and in layout_template you insert content where you want.

Malthe Borch

unread,
May 4, 2013, 3:17:35 AM5/4/13
to pylons-...@googlegroups.com
The CHAMELEON_CACHE environment variable allows you to specify a
directory for compiled files. This is pretty useful during development
where you typically can't tolerate a non-trivial warmup. Chameleon's
pretty fast at rendering templates, but it's definitely on the slow to
very slow side in parsing and compiling them.

\malthe

Malthe Borch

unread,
May 4, 2013, 3:21:13 AM5/4/13
to pylons-...@googlegroups.com
Chameleon makes it pretty easy I'd say to use a site template:

<html metal:use-macro="load: ../master.pt">
<div metal:fill-slot="content">
<h1>${title}</h1>
...
</div>
</html>

You can also use ``metal:extend-macro`` to make a linear
specialization that keeps slots "fillable". For instance, you might
specialize your "master.pt" template into a "content.pt" template that
is then the basis of all content object views.

\malthe

Mike Orr

unread,
May 4, 2013, 11:20:39 AM5/4/13
to pylons-...@googlegroups.com
On Sat, May 4, 2013 at 12:21 AM, Malthe Borch <mbo...@gmail.com> wrote:
On 4 May 2013 00:48, Mike Orr <slugg...@gmail.com> wrote:
> Are there any good examples around of using Chameleon with a site template
> macro?

Chameleon makes it pretty easy I'd say to use a site template:

<html metal:use-macro="load: ../master.pt">
   <div metal:fill-slot="content">
      <h1>${title}</h1>
      ...
   </div>
</html>

You can also use ``metal:extend-macro`` to make a linear
specialization that keeps slots "fillable". For instance, you might
specialize your "master.pt" template into a "content.pt" template that
is then the basis of all content object views.


I saw extend-macro but didn't quite understand what it does or how to use it. How would you use it with your example above?
 

Mike Orr

unread,
May 8, 2013, 5:12:32 PM5/8/13
to pylons-...@googlegroups.com
On Sat, May 4, 2013 at 12:21 AM, Malthe Borch <mbo...@gmail.com> wrote:
Chameleon makes it pretty easy I'd say to use a site template:

<html metal:use-macro="load: ../master.pt">
   <div metal:fill-slot="content">
      <h1>${title}</h1>
      ...
   </div>
</html>

You can also use ``metal:extend-macro`` to make a linear
specialization that keeps slots "fillable". For instance, you might
specialize your "master.pt" template into a "content.pt" template that
is then the basis of all content object views.



So the last part I don't understand is now to select parts of the macro chain. For instance, I have a site template, section template, and page template. I can specify fill content in the page template, but how do I do the opposite, or access base content in the page template? Or is that something you can't do in Chameleon?

So in Mako's base template I can use ${foo()} to get the local content, ${self.foo()} to get the top-level (subclass) content, or ${next.foo()} to get the next level's content (either a intermediate template or the page template). Likewise, in a page template I can use ${parent.foo()} to get content from an ancestor (superclass) template.

'self' maps straightforwardly to Chameleon's slots, but how do you do the equivalent of 'next' and 'parent'? For instance, if some page templates want to put the base content in an unusual order, and others want to overrride it completely, but you don't want to define duplicate content at multiple levels.

Also, can I provide a title in the page template and use it as part of the title in the site template?

Page:  <title>My Title</title>
Site: <title>${page_title} | SiteName</title>

Or would I have to do something monsterous like this?

Site: <title><title metal:define-slot="title"  tal:omit-tag="1">Default Title</title></title>
Page: <title metal:fill-slot="title">Page Title</title>

One, can I nest the <title> tag like this? Two, can I define a slot on one tag but fill it on a different tag, or does it have to be the same tag name? If it's different, which tag name has precedence?

In Mako I do my titles like this:

===
## Site template
<title>${ht_title()}</title>
<h1>${title()}</title>
<%def name="ht_title">${title()}</%def>
<%def name="title">Default Title</%def>

## Page template.
<%inherit file="/base/site.html" />
## No title tag.
<%def name="title()">Page Title</%def>
===

Malthe Borch

unread,
May 10, 2013, 4:02:19 AM5/10/13
to pylons-...@googlegroups.com
On 8 May 2013 23:12, Mike Orr <slugg...@gmail.com> wrote:
> 'self' maps straightforwardly to Chameleon's slots, but how do you do the
> equivalent of 'next' and 'parent'? For instance, if some page templates want
> to put the base content in an unusual order, and others want to overrride it
> completely, but you don't want to define duplicate content at multiple
> levels.

The pattern that's usually used is:

<metal:block fill-slot="content">
...
<metal:block define-slot="content">
...
</metal:block>
...
</metal:block>

This would be a template that sits in-between a master template and
the top-level template.

> Also, can I provide a title in the page template and use it as part of the
> title in the site template?

Yep –

<head>
<title metal:define-slot="title">${page_title|string:not sure}</title>
</head>

You can then fill this slot from anywhere in the "chain" of templates
that use and extend each other.

> Page: <title>My Title</title>
> Site: <title>${page_title} | SiteName</title>

You do need to use ``metal:fill=slot``.

> Or would I have to do something monsterous like this?
>
> Site: <title><title metal:define-slot="title" tal:omit-tag="1">Default
> Title</title></title>
> Page: <title metal:fill-slot="title">Page Title</title>

I would probably just define the slot on the <title> element itself –
or alternatively, use a <metal:block ... /> construct (note that the
term "block" is just often used, it doesn't carry special meaning).

> One, can I nest the <title> tag like this? Two, can I define a slot on one
> tag but fill it on a different tag, or does it have to be the same tag name?
> If it's different, which tag name has precedence?

You can define two slots with the same name and fill it with a single
expression, yes. That's pretty useful for things like the page title
where you often want to apply it to both <title> and <h1>.

\malthe

Nico Poppelier

unread,
Aug 10, 2015, 5:05:30 PM8/10/15
to pylons-discuss, mbo...@gmail.com
I'm trying to get template inheritance working they way it is described in this thread, but get the error message below when I try to load the templates: " LookupError: Unknown expression type: 'load'."

Template 1: base.xml

<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" metal:define-macro="base">
  <head><title>TITLE</title></head>
  <body>
  <div metal:define-slot="content">content</div>
  </body>
</html>

Template 2: default.xml
<div metal:use-macro="load: base.xml">
  <div metal:fill-slot="content">
  <p>one article as content</p>
  </div>
</div>

The files base.xml and default.xml are in the same directory.

Any help is appreciated!

Nico

Nico Poppelier

unread,
Aug 10, 2015, 5:05:33 PM8/10/15
to Malthe Borch, pylons-discuss
Malthe,

Thanks for the quick reply! I read the documentation twice to find out what I was doing wrong. Did I miss a paragraph about load and file-based templates?

Anyway: my application uses string-based templates. The contents of all files *.xml are read when the application initializes, the resulting strings are passed to chameleon.PageTemplate, and the compiled templates are stored:

template['base'] = PageTemplate(read_file('base.xml'))
template['default'] = PageTemplate(read_file('default.xml'))

What is the best way for the 'default' template to refer to the 'base' template?

Regards, Nico

Op 10-08-15 om 18:13 schreef Malthe Borch:
Note that load is only available on file-based templates. Is that what you're using?

Nico Poppelier

unread,
Aug 10, 2015, 5:05:33 PM8/10/15
to Malthe Borch, pylons-discuss
OK, but isn't there a way to pass the dictionary 'template' to the template 'default' such that this template refers to the 'base' macro in template['base']? Presently, the templates are read from a filesystem, but in future I would like to be able to read them from a (non-SQL) database. That's why I'm experimenting with string-based templates.

If not, I will investigate the PageTemplateFile option.

Thanks -- Nico


Op 10-08-15 om 19:42 schreef Malthe Borch:
String-based templates are really kind of awkward when it comes to "load". It's possible to wire it up, but you will need to do some work. It's easier to simply use PageTemplateFile because it has the "load" expression compiler set up already.
Reply all
Reply to author
Forward
0 new messages