Martijn Faassen posted two entries on alternative template languages for
Zope 3:

The idea behind this is simple: Templates should be data-driven! That is,
they should contain no calls, no logic (other than for display) and no other
monkey-business at all. It might be easiest to explain why this is a good
idea by explaining the problems with NOT doing it.

In the beginning there was DTML

DTML was the first template language for Zope. Although a huge improvement
on how PHP and ASP templates work, DTMLs syntax, gets ugly pretty quickly.
Also, people tended to write complete aplications in DTML. That's OK; it was
designed to do that, Python Scripts didn't exist in the first versions of
Zope. DTML was the replacement of PHPand ASP. But this quickly tirned ugly
and complicated (as it does in ASP and PHP too). Something better was

Let there be TAL

ZPT was the next step: Better syntax (it's more verbose, but it is
consistent, easy and doesn't degrade into uglyness), and less intelligence
and magic. Again, a huge step forward. But if you look at the typical CMF
template, you'll see masses of logic, usually complex logic that makes the
templates hard to understand and error prone.

This happens because templates in Zope2 access objects. They have a context
variable where you get the object you are displaying, and you can access the
objects attributes and methods. You can also call python expressions. In
short, even the new cleaner ZPTs doesn't enforce a strict enough separation
between logic and presentation. You can still do too much.

So what if we don't do anything of this? We just have data, and display it?
Is that feasible with ZPTs? Yes, absolutely. What you need is to somehow
call a method before displaying the template, that fetches all the data and
does everything that should be done before displaying.

Keeping your templates clean.

Luckily, we don't need a new templating system to do this, ZPT allows you to
do too much, but it doens't force you too. You can do this by convention.

Zope3 has a system of view classes, where the class is supposed to do
exactly, this:  prepare and react to the data for and from the
template. So in Zope 3 you can prepare everything you need, do any actions
that should be done and set the data to be displayed as attributes on the
view object from the views init method. All in pure, standard python. No
longer should you need to call any more methods in the template, and you
don't need to do any arithmetic, it's all done beforehand.

In CMF you don't have a view class, but there can call a python script,
that returns a dictionary with the data to be displayed, with statements
like tal:define="data context/update_script". Then you access it with
"data/key" later in the ZPT.

Python statement considered harmful

As a rule of thumb, you should avoid any "python:" statements in ZPT, and
you should also avoid using "context" unless it is to use another template
via a macro. If you avoid this, you are a long way to keeping your ZPTs
clean, and your code understandable.

(Post originally written by Lennart Regebro on the old Nuxeo blogs.)