Skip to content

Templates: The right amount of Push

October 30, 2007

[Update: I seem to have been thinking of something else when I wrote about Kid. Kid is not push-fundamentalistic at all. Fixed.]

When it comes to choosing a template language amongst the hoard of templating languages out there, there are basically a couple of questions that are being debated. One is the question of XML vs Text, and the other one is the debate about Push vs Pull, i.e. should the data be prepared in Python and pushed to the template, or should the template be powerful enough to pull in the data itself.

On the question of XML vs Text, I have no opinion, except that it should always be possible to create a template that is valid XHTML if you want to. That means some sort of attribute language when it comes to conditionals and loops (so, no DTML at least).

When it comes to Push vs Pull, I’ve blogged about the problem with having to powerful templating languages that does a lot of logic and pulling before. Taking this to the extremes gives us languages such as Templess and ClearSilver, where each variable that should be displayed has to be set into a dictionary that is then pushed to the template for rendering. This is often seen as a bit complicated an cumbersome, so at the other end we have languages such as Genshi. It’s become very hyped, possibly because it stomps all over the question of XML vs Text, and has two types of templates, and also happily mixes the XML-friendly py:content syntax with text based $foo-syntax. So basically, you can have both your XML cake and your Text cake. And eat them.

Far from being push-fundamentalistic Genshi has gone fundamental in the other direction. Not only does it allow you to execute little python statements, like ZPT does, it actually allows you to escape out into pure python, PHP/ASP-style. Thereby you can, if you want, write a whole system in Genshi without actually having any other Python-file in the system except the one that defines up the templates.

Now, that’s all and well if you are the only one to modify the templates. But when you are writing an open source software that a community is developing, or if you work in a setting where you have bother experienced, disciplined programmers and new enthusiastic hackers, then this “templates can do anything”-attitude becomes downright scary. It opens up the possibility of tons crappy, obfuscated, supposedly clever script-kiddie hacks in code that is supposed to be production-quality. It puts a lot more responsibility onto code reviewing, which is not a good idea, generally.

So, yes, in principle I’m all for push. But within reason, because as noted, otherwise it gets to complicated and you get complete insanity as an overreaction to the pointless work. Most templates in python are views on objects, after all. Why should you to use your template need to do this:

namespace = {'title': obj.title,
            'description': obj.description,
            'text': obj.getText()}
return MyTemplate(namespace)

And then in your template again use the variable title, description, text. This means that for each attribute you want from an object you have to actually type that attribute three times. This becomes even more ridiculous in the Zope-world, where we have the concept of “view” objects that contain all the logic and attribute calculations.

No, the correct amount of push is that you should only be allowed to access the objects that are pushed to the templates. But limiting those objects to text only doesn’t make any sense. Of course you should allow attribute access, so that all you need to do is

return MyTemplate(context=object)

Or something similar, and then have the template be able to access those attributes directly.

But, you say, isn’t this taking a dangerous step towards pull? What is the next step? Should you be allowed to call methods? Sure. With parameters? I don’t know, but possibly. What is then to stop you from pushing in a method that lets you traverse the objects and thereby pulling in data, or even execute python code? Well, nothing. But instead of giving unlimited options and two hundred million ways of confusing the code to everybody, you made it clear that there is one good and easy way to do it: Push in objects. If people then want to be contrarywise and weird, it’s up to them.

I’ve yet to see a templating system that does this right, which is to say, allow attribute access but not python statements. I’m keeping my eyes open for Alexander Limi + friends as yet unnamed templating language and holding my thumbs they get it right.

About these ads

From → plone, python, theming, zope

11 Comments
  1. Of course it is annoying to be limited to the set of dictionary values the original programmer gives you and it is annoying as well to debug code embedded in page templates which might get data from you-don’t-know and might break easily if some component is changed.

    So in the end you might want certain standard sets of data and methods to be available (like title, description etc.) and maybe additional ones provided by a view.

    But in Zope3/Plone don’t we have interfaces for these things. We might allow certain interfaces to be used. Most object have a common interface set and where it’s not sufficient you can still extend it with a view or adapter.

    I think it just needs to be sure that logic is defined in the right and well defined place and if something is changed everybody knows where or at least how to find that place.

    Well, in Zope3/Plone we have well defined interfaces which should be used and nothing else. Of course it is annoy

  2. Martijn Faassen permalink

    I’m not sure whether you characterize Kid very correctly. As far I’ve seen, it’s mostly just like Genshi: you can do inline Python code, and you access things in dictionaries in arbitrary-Python ways, allowing you to pull data out. I recall Genshi for a while didn’t have the Python escaping yet, but Kid did have it.

    Two pure-push languages are ClearSilver and XSLT (ignoring any custom extension functions).

  3. Lennart Regebro permalink

    Hm. I seem to have gotten Kid mixed up with something else in my head. :-( I’ll update the text.

  4. Lennart Regebro permalink

    Updated! Also, it would be interesting with a discussion of where to put the limit. I’m not sure myself.

    I’d like to be able call methods, as mentioned above, at least so it’s possible to call methods on the view. But pass in parameters? To do that you’d probably have to exec the expression, and then nothing really stops you from starting to make stupid stuff like “view.isLocal() and ‘local’ or ‘notlocal’” and then you have already ventured to far.

  5. Martijn Faassen permalink

    My views on all this. There are two distinct approaches:

    * total freedom for the Python programmer. Good for small teams of experienced developers. We want freedom here for the same reasons we want Python – it doesn’t artificially restrict you in any way. We know what we’re doing.

    * strong restrictions. Good for larger teams of not necessarily experienced developers, or even developers at all, and large, long running open projects. No side effects or even calls can be triggered from the templates *at all* . You pass in a dictionary, or some tree structure like ClearSilver’s HDF, or XSLT’s XML, and there’s nothing that is going to cause a call into the system. Calls into the system can cause weird errors deep within the system.

    In the face of practicality you could make compromises on the strong restrictions approach, allowing a few calls here and there just to make life easier. With a few well-chosen calls to reliable libraries we might make people’s life a lot easier.

    To prevent completely messy templates, you could also start introducing restrictions into the total freedom approach. The question is how much mess this really cleans up.

    I see less need to put actual restrictions on the total freedom approach. Good idioms and practices, yes, but restrictions? I’m not sure whether a few restrictions really help. In fact, we’ve seen with ZPT that a few restrictions don’t really seem to help all that much. Are more restrictions the answer? I’m not sure. And how many? I don’t know either. It probably also depends on how obscure the errors are that the underlying framework raises.

    With Grok, I’d like to experiment with both. We almost have Genshi support in. We should also investigate putting something like XSLT in next. Or templess, which is mostly strong restrictions but does allow some side effects.

    Then we go build a few large applications and maintain them for years and we see where we end up. :)

  6. Lennart Regebro permalink

    “With a few well-chosen calls to reliable libraries we might make people’s life a lot easier.”

    With views I don’t know if you need this, as you always can do that call in the view. I’m leaning towards not allowing explicit method calling, but automatially calling callables. And attribute access of course.

  7. Lennart Regebro permalink

    This comment from http://www.jarn.com/blog/optimizing-navigation-tree-templates
    on Alexander Limis and “Mike from YouTube”s (Is that his real name? :) ) templateing system was worrying:

    “the data is assembled in a dictionary,”

    Hmm. Did that mean pure text push only? Nah, looking at the code that is generated by this template “compiling” to python, the result is something like this:

    https://svn.plone.org/svn/collective/experimental.portlet.navtree/trunk/experimental/portlet/navtree/navigation.py

    As we see there are clear examples of python-calls, like so:

    view.navigation_root().absolute_url()

    This is more python-power than I want to be honest, but I also notice that this doesn’t mean you gets ZPTs traversal power. You still have to push all the objects that you need to access. That you can do evilness as “foo = foo is None and bar or foo” is an unfortunate drawback with this scheme, but at least making ugly stuff requires stupid hackery like that, while ZPT almost invite you to do logic in the templates.

    As soon as this templating system gets released I’m gonna integrate it in Grok, and try it out. It seems like the best option so far.

  8. Thanks for the release, very cool…

    Nice article, too. Note that Templess does allow you to use objects instead of dicts, there’s a wrapper for objects available as templess.objectcontext, although it’s very simple it does as you describe (methods are called too, though without arguments).

    As you might have guessed I like push better than pull, although I’m not very religious about it… I generally do like to keep the logic (and clutter ;) in the code, though, and not just in projects where non-programmers work on the templates: I like to have clean, simple templates and don’t mind a little extra work code to achieve that goal… But it’s a matter of taste, mostly, I think.

Trackbacks & Pingbacks

  1. Genshi + Grok = True: megrok.genshi 0.9 released! « Regebro on Python and Zope
  2. Templess 0.3 released « Regebro on Python and Zope

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 1,225 other followers

%d bloggers like this: