So as I further my side journey into Python, or Pylons to be more exact, one of the decent things I’ve run into is that Mako templating system. What is that? It’s what runs along side of Pylons (Or at least one of many) for displaying the View side of the whole MVC thing. Now if you’re here, chances are you just searched on this so I wouldn’t go into a huge thing about Pylons or Mako. I’ll just get to the damn point.
This is just an example of a three layer template I use to help with pumping out pages with out repeating a lot of code. The nice thing about Mako is how simple it is to have multiple layers of templates to make up a single page. This is basically done with using the next keyword.
What is next?
Mako has a system that works something like an abstract class. A page template can define a certain area in a method like way and like an abstract method, there is no method body. Any page template that “inherits” the base has to fill in the body or create an abstract method itself to call the original method.
Now with that being said, there are two key words for doing this and the default keyword is self. Problem with self is that it looks at the top most template only. So if you have say 3 layers:
BasePage -> SecondLayer -> ThirdLayer
self will always look to the third layer:
BasePage -> ThirdLayer
While second layer is all like, “Yeah whateve”. Overall, this isn’t very helpful if you want a sort of chain like effect. Its basically like a base class not giving a flying… not caring about what any child classes do except the top most child class. What if you have a div that holds content on the base, and the second layer has its own content area to hold the third layer. This would be useless if you used self since that second layer would just be ignored. Sad day. This is where next comes in. Next, like an abstract method, basically just sets a place holder for the next template to “inherit” the said template. Now the danger of next is that just like an abstract method, the system will be all “Waaaaaah, you didn’t override the method. Waaaaaah.” if you forget to define the method in the next layer. The huge advantage is you can create a nice consistent design in which you can just bang out child templates since you know exactly what the baser (Yeah I wrote baser.) page will have.
On to the example. And this is an example of what a template structure could look like.
The base page:
<html> <head> //next.title will allow all children to add on to the title <title>First Level - ${next.title()} </title> //next.styleSheetIncludes will allow all children to add any included css files if needed. <link rel="Stylesheet" href="${h.url('/css/base.css')}" /> ${next.styleSheetIncludes()} //next.javascriptIncludes will allow all children to add any included javascript files if needed. <script type="text/javascript" src="${h.url('/scripts/base.js')}"></script> ${next.javascriptIncludes()} //next.styleSheet allow all children to add any page specific css that wasn't included in files. Why // have the style tags instead of just having the ${next.styleSheet()}. Well you could but then you would // end up with more than one style tag when the page is built. <style type="text/css"> ${next.styleSheet()} </style> //next.javascript allows all children to add any page specific javascript that wasn't included in files. This // follow the same idea as the next.styleSheet above. Why have a possible 3...4...5... script tag when // the child templates can just add to this one? <script type="text/javascript"> function firstLevel(){ } ${next.javascript()} //next.javascript allows all children to add any page jquery document.ready javascript that is specific to the // given child. Once again this is an example of add to instead of repeating a section jQuery(document).ready( function () { jQuery('button').button(); ${next.documentReady()} } ); </script> </head> <body> <div class="header"> </div> <div class="bodyContainer"> //This will be where the child html will fall. ${next.body()} </div> </div> </body> </html>
The second layer:
<%inherit file="base.html" /> <%def name="title()"> - Second Level </%def> <%def name="styleSheetIncludes()"> <link rel="Stylesheet" href="${h.url('/css/secondLevel.css')}" /> ${next.styleSheetIncludes} </%def> <%def name="styleSheet()"> ${next.styleSheet()} </%def> <%def name="javascriptIncludes()"> <script type="text/javascript" src="${h.url('/scripts/secondLevel.js')}"></script> ${next.javascriptIncludes()} </%def> <%def name="javascript()"> function secondLevel(){ //Method in second level } ${next.javascript()} </%def> <%def name="documentReady()"> //nothing here on second level ${next.documentReady()} </%def> <%def name="body()"> <div class="leftMenu"> <a href="something.html">something</a> <a href="somethingElse.html">something else</a> </div> <div class="rightArea"> ${next.body()} </div> </%def>
As you can see, all the abstract areas defined in the base are being used by this layer and then this layer is in turn adding its own abstract methods that share the same name as the base template’s method. The nice this is you can do this using the next keyword as the current template will only respond to the template immediately inheriting it. You don’t get any kind of method name clash.
And the final layer:
<%inherit file="secondLevel.html" /> <%def name="title()"> - Third Level </%def> <%def name="styleSheetIncludes()"> <link rel="Stylesheet" href="${h.url('/css/thirdLevel.css')}" /> </%def> <%def name="styleSheet()"> .thirdLevel { } </%def> <%def name="javascriptIncludes()"> <script type="text/javascript" src="${h.url('/scripts/thirdLevel.js')}"></script> </%def> <%def name="javascript()"> function thirdLevel(){ //Method in second level } </%def> <%def name="documentReady()"> //nothing here on third level </%def> <%def name="body()"> <div> Hi from third level</div> </%def>
The third layer now closes off the chain by no longer adding any abstract methods of its own. Now if I knew there could be yet another layer, all I would have to do is use the same naming convention and add the needed next.methods.
And this is what the source should look like:
<html> <head> <title>First Level - - Second Level - Third Level </title> <link rel="Stylesheet" href="${h.url('/css/base.css')}" /> <link rel="Stylesheet" href="${h.url('/css/secondLevel.css')}" /> <link rel="Stylesheet" href="${h.url('/css/thirdLevel.css')}" /> <style type="text/css"> .thirdLevel { } </style> <script type="text/javascript" src="${h.url('/scripts/base.js')}"></script> <script type="text/javascript" src="${h.url('/scripts/secondLevel.js')}"></script> <script type="text/javascript" src="${h.url('/scripts/thirdLevel.js')}"></script> <script type="text/javascript"> function firstLevel(){ } function secondLevel(){ //Method in second level } function thirdLevel(){ //Method in second level } jQuery(document).ready( function () { jQuery('button').button(); //nothing here on second level //nothing here on third level }); </script> </head> <body> <div class="header"> </div> <div class="bodyContainer"> <div class="leftMenu"> <a href="something.html">something</a> <a href="somethingElse.html">something else</a> </div> <div class="rightArea"> <div> Hi from third level</div> </div> </div> </div> </body> </html>
As you can see, things like the ${next.documentReady()} really helped to keep the source code clean and avoid repeated code on the source side. Now go forth, all 2 of you… including me…, and use this knowledge to do something.