* Home * SlinkP Software Projects * Random Zope Notes * Python web templates revisited
Last updated Jun 30, 2007 6:45 pm Universal

PyMeld2: A Proposal for Next Generation Templates for Python Web Apps

Author: Paul Winkler, http://www.slinkp.com

This proposal grew out of a discussion on plope.com

I have removed links to the experimental Meld2 code. It has been supplanted by Chris McDonough's Meld3

Disclaimer

This page is a proposal only. It is not documentation for any specific implementation such as Meld3.

Rationale

Every web framework on the planet (and some standalone renegades) has a template system. These generally take one of two approaches: Implement every feature you could want in the templating language (a la DTML, ZPT), and/or require you to embed Python in the template (Kid etc).

IMHO these approaches lead to much complexity and too many new concepts for newbies to learn; and the templates tend to be unfriendly for round-trip collaboration with designers (ranging from "impossible" for DTML to "possible but still a bit scary" for ZPT).

The third approach is to radically simplify the template language and offload the work into some associated python code. (You can of course take this approach in any template language, just by using as few of its features as possible and relying on python code to do the heavy lifting) but in practice the temptation to take the easy / sloppy route means that you will have to work with other peoples' nasty, unreadable, poorly-factored crap a lot of the time.)

There are three examples I know of of the third approach.

So, I propose to start with a PyMeld-like approach, but fix its shortcomings.

For purposes of this document I'm calling the project "Meld2". I thought of calling it "Teng", for "Template Engine Next Generation", but there's already a template system at teng.sourceforge.net! (It looks to be a minor extension to existing systems, e.g. PHP.)

Goals:

So far, PyMeld already satisfies all of the above. Where PyMeld falls down:

Common Features of Templating Languages

This is a sort of catalog of things that should be taken care of by the python API for meld2. XXX put HTMLTemplate in here too.

Summary of Feature List

After looking through that list, it may be that the only thing that PyMeld doesn't provide enough help for is repetition. But repetition is really important.

Repetition: Casey Duncan's proposal

(from http://plope.com/Members/casey/tal_inheritance/talkback/1131264921)

Casey writes:

    ...each element in the template has a method
    'zip_repeat(iterable)'. When called this method returns a
    generator which first removes the template element from the
    document, then yields tuples of '(element.clone(),
    iterable.next())'. Each time a cloned element is yielded, it is
    inserted in the document right after the last element (the first
    element is inserted where the original element was). The result is
    similar to "tal:repeat", especially if you iterate it in a
    for-loop. Here's an example. Here is a snippet of the document
    (for now we continue overloading the tag "id" for simplicity)::

     <table>
       <tr>     
         <th>Title</th>
         <th>Description</th>
       </tr>
         <tr id="doc_item">
           <td id="title">Document Title</td>
           <td id="description">Document Description</td>
       </tr>
     </table>

    Here is the python "transform" to populate it, imagine that we
    have loaded the above into a Template instance named
    "template". __getitem__() on Template objects returns the element
    with that id::

     for tr, doc in template['doc_item'].zip_repeat(context.listFolderContents()):
         tr['title'].content = doc.getTitle()
         tr['description'].content = doc.getDescription()

    So iterating zip_repeat() yields clones of the original table row
    preplaced in the DOM where you want it, along with each document
    in the folder so you can modify the row content or anything else
    you want. When rendered, it might look something like this::

     <table>
       <tr>
         <th>Title</th>
         <th>Description</th>
       </tr>
       <tr id="doc_item">
         <td id="title">Foo Document</td>
         <td id="description">The Document of Foo</td>
       </tr>
       <tr id="doc_item">
         <td id="title">Bar Document</td>
         <td id="description">The Document of Bar</td>
       </tr>
       <tr id="doc_item">
         <td id="title">Baz Document</td>
         <td id="description">The Document of Baz baby!</td>
       </tr>
     </table>

    Probably the biggest problem I see with this is that we have
    multiple tags with the same "id" value which is technically not
    allowed. So that's probably a vote for using a custom namespace
    for identifying elements used by templates. Either way the ids
    will probably need to be munged to keep thing unabiguous in cases
    where a pipeline of template "transforms" like above are employed.

(End of quote from Casey.)

The last paragraph matches my conclusions too. If we do things as I proposed above in the notes on repeating, the input would look like:

     <table>
       <tr>     
         <th>Title</th>
         <th>Description</th>
       </tr>
         <tr meld:id="doc_item">
           <td meld:id="title">Document Title</td>
           <td meld:id="description">Document Description</td>
       </tr>
     </table>

and the output of Casey's code would look like:

     <table>
       <tr>
         <th>Title</th>
         <th>Description</th>
       </tr>
       <tr meld:id="doc_item/0">
         <td meld:id="title">Foo Document</td>
         <td meld:id="description">The Document of Foo</td>
       </tr>
       <tr meld:id="doc_item/1">
         <td meld:id="title">Bar Document</td>
         <td meld:id="description">The Document of Bar</td>
       </tr>
       <tr meld:id="doc_item/2">
         <td meld:id="title">Baz Document</td>
         <td meld:id="description">The Document of Baz baby!</td>
       </tr>
     </table>

Implementation Status

Meld3 implements pretty much everything here, although the API has changed a bit, so it doesn't look quite like Casey's example anymore, and it does not implement the auto-fixing of repeated ids.


     Send me some mail slinkP home page Powered by Zope