The Artima Developer Community
Sponsored Link

Weblogs Forum
Django vs. Cheetah: 1-0

86 replies on 6 pages. Most recent reply: Jan 28, 2008 1:34 AM by Johnny Stovall

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 86 replies on 6 pages [ « | 1 2 3 4 5 6 | » ]
Fredrik Lundh

Posts: 16
Nickname: effbot
Registered: Mar, 2005

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 9:11 AM
Reply to this message Reply
Advertisement
> Anyone know if it's possible to use htmltext with Django?

You don't have to run things through the Django templates, so that shouldn't be very hard.

(I still recommend Django's templating for boilerplate and overall site design, but generating the body (or other fragments) with a tool that's better suited for your application works perfectly well.)

Christian Wyglendowski

Posts: 1
Nickname: dowski
Registered: Jun, 2004

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 9:39 AM
Reply to this message Reply
> Django and Cheetah both define a 'Template' class.
> Python's standard library also has a Template class (in
> n string.py), which serves a similar purpose (but with
> only a fraction of the functionality). All these have
> different APIs. But are the differences important? It
> seems pretty arbitrary whether to use
> Template("...").render(locals())
> (Django), or str(Template("...", searchList=[locals()]))`
> (Cheetah) or ``Template("...").substitute(locals())
> (string.py). Perhaps we could attempt some
> standardization here similar to WSGI?</p>

Precisely. TurboGears, Pylons and my Buffet templating filter for CherryPy use a common API and templating engine "plugins" to render pages based on templates. It is more of an ad-hoc standard ATM, but could be more official I suppose.

When you get down to it, most templates are rendered by passing a template file (or string) and a mapping of parameters to some sort of "render" callable.

There are currently plugins for: Cheetah, Kid, Myghty, XSLT, Python 2.4 string.Templates, STAN, formencode.htmlgen.

See the "interface" for a plugin here: http://www.turbogears.org/docs/plugins/template.html

Good luck deciding.

Christian Wyglendowski
CherryPy Team

Adrian Holovaty

Posts: 5
Nickname: holovaty
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 9:57 AM
Reply to this message Reply
Hi Guido,

Sorry for your easy_install problems on Python 2.5. Note that you should be able to simply copy the "django/" directory within the Django tarball to your site-packages directory, and it should Just Work. (Frankly, the only reason we're using setuptools/easy_install is because it automates the creation of the MANIFEST file when we're creating packages.)

One of our goals is to make the different Django components downloadable on their own, so that people can use Django templates without having to download the whole framework. As you note, this will involve removing the need for the DJANGO_SETTINGS_MODULE environment variable, which should be an easy change.

Cheers,
Adrian

P. V.

Posts: 1
Nickname: sundance
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 9:58 AM
Reply to this message Reply
Hello Guido,

Thank you for this insightful article. I am currently looking into Python-based Web development possibilities, myself (I work in a mostly-PHP company, and would seriously like to have a solid Python-based alternative to suggest, should management ever ask).

My own research had me put TurboGears at the top of the list of projects to keep in mind, in good part because I felt it's pretty good at letting you use your own modules instead of its own if you want (or need) to. And, like you, I do want to, generally.

So I was sort of hoping for your own thoughts on that particular project, and in particular, I was wondering if you were still intending to look into it and post about it?

Either way, I'm highly looking forward to reading more from you about this very active topic!

Thanks again. :)

Ville Vainio

Posts: 1
Nickname: vivainio
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 10:03 AM
Reply to this message Reply
Empy hasn't come out with a new version in a while, but it's notation appears to be the simplest and most pythonic. It only reserves @.

Here are some copy-pasted examples:


The value of x is @x.
The ith value of a is @a[i].
The result of calling f with q is @f(q).
2 + 2 is @(2 + 2).

@{x = 123}


Control structures:

@# If `person' is alive, show their age.
@person.name is @
@[if person.isAlive]@person.age@[else]dead@[end if].
@[def f(x, y, z=2, *args, **keywords)]...@[end def]

Jaroslaw Zabiello

Posts: 2
Nickname: jzabiello
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 11:00 AM
Reply to this message Reply
Cheetah do not need to use dictionary aproach, nor searchList=[names] as wrote Guido. So you can use:


from Cheetah.Template import Template
t = Template("<h1>Hello $name</h1>")
t.name = "Tavis"
print t
t.name = "Ian"
print t



t = Template("<h1>Hello $name</h1>", {'name':'Tavis'})
print t.respond()


or


print Template("<h1>Hello $name</h1>", {'name':'Tavis'}).respond()


Guido was wrong thinking that Cheetah always raises an exception for unfound names. It is optional and intentional (usefull if you want to catch any errors very early). But this behaviour can be changed:

#errorCatcher Echo
#set $iExist = 'Here I am!'
Here's a good placeholder: $iExist
Here's bad placeholder: $iDontExist


The output will be:

Here's a good placeholder: Here I am!
Here's bad placeholder: $iDontExist

More in:
http://www.cheetahtemplate.org/docs/users_guide_html_multipage/errorHandling.errorCatcher.html

Django looks like mixin of Cheetah and Smarty (http://smarty.php.net). I like its piping syntax for modifiers. But I hate it's "if" syntax. There is no "elif" nor "and". Eg. you cannot use the following syntax:

{% if x and y %}
yes
{% else %}
no
{% endif %}

nor

{% if x==1 %}
one
{% elif x==2 %}
two
{% else %}
other
{% endif %}

You can use only this:

{% if %}
{if y %}
yes
{% else %}
no
{% endif %}
{% endif %}

It does not like great for me. Cheetah is much more readable.

Guido van van Rossum

Posts: 359
Nickname: guido
Registered: Apr, 2003

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 11:20 AM
Reply to this message Reply
> Cheetah do not need to use dictionary aproach, nor
> searchList=[names] as wrote Guido. So you can use:
[...]
> t = Template("<h1>Hello $name</h1>", {'name':'Tavis'})
> print t.respond()

This (and other examples you show) still requires the dict to be passed to the Template constructor instead of to the respond() call, which is my real gripe. I know there are ways around that too, but my point is that the recommended approach is otherwise.

> Guido was wrong thinking that Cheetah always raises an
> exception for unfound names. It is optional and
> intentional (usefull if you want to catch any errors very
> early).

I read that before I posted, but they state very clearly that they don't want you to use this to provide default values for substitutions; they only want you to use it for debugging. Again, the recommended approach is wrong IMO and that counts more than what you can hack. Fighting the system should not be a standard behavior.

> Eg. you cannot use the following syntax:
> {% if x and y %}
> nor
> {% if x==1 %}

Point taken. But arguably you are now putting application logic in the template.

William Dodé

Posts: 2
Nickname: wilk
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 11:44 AM
Reply to this message Reply
> > Eg. you cannot use the following syntax:
> > {% if x and y %}
> > nor
> > {% if x==1 %}
>
> Point taken. But arguably you are now putting application
> logic in the template.

It can be design logic and not application logic :

#if $ok
<b>OK</b>
#else
<i>NOK</i>
#end if

I like cheetah because my graphist understand very easily theses little scripts inside the template.
I've also succeed using cheetah inside docutils documents by writers.

Ben Bangert

Posts: 6
Nickname: bbangert
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 11:54 AM
Reply to this message Reply
I'm really surprised you haven't looked at Myghty (http://www.myghty.org/). Myghty is a port of the extremely popular Perl templating system HTML::Mason used by major websites like del.icio.us, Amazon.com, and many many more.

The templating solution it provides is far more powerful than any of the others I've seen, and allows for sophisticated caching when speed is a concern.

Regarding a standard, there is sort of a standard developing, that TurboGears has pioneered, and Pylons also supports. It's called template plug-ins:
http://www.turbogears.com/docs/plugins/template.html

You get a consistent interface to use a variety of template languages of your choice. If the Django templates can be used completely on their own, I'm not sure why they aren't supporting this developing standard.

mike bayer

Posts: 22
Nickname: zzzeek
Registered: Jan, 2005

the example, in Myghty Posted: Jan 31, 2006 12:02 PM
Reply to this message Reply
import myghty.interp as interp
interp = interp.Interpreter(out_buffer=sys.stdout)

# pull arguments from ARGS
c = interp.make_component("<h1>Hello <% ARGS['name'] %></h1>")

# or pre-declare args in your component
c = interp.make_component("<%args>name</%args><h1>Hello <% name %></h1>")

# execute with request args
interp.execute(c, request_args={'name':'phillip'})

# execute with request args, send the output somehwere else
interp.execute(c, request_args={'name':'adrian'}, out_buffer=mybuf)

Shannon -jj Behrens

Posts: 12
Nickname: jjinux
Registered: Aug, 2005

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 12:27 PM
Reply to this message Reply
I like Cheetah. The whole compile to Python thing happens behind my back in Aquarium, and I haven't found it to be brittle. At my company, it's always programmers editing templates, so I like to treat templates like classes. That is:

o aquariumFactory() can return either an instance of a template or an instance of some class, and the caller need not know the difference.

o I like being able to think in Python when writing a template. I picked Cheetah because I liked the syntax. I think inheritance and methods are must haves in a templating language. It's not that I put business logic in my template, it's just that I apply DRY to templates too ;)

o I never type things like 't = Template("<h1>Hello $name</h1>", searchList=[names])'. I decide ahead of time whether the file should be a Python class or a Cheetah template. This type of setup grunt work should just happen behind my back.

I *do* pre-compile Cheetah down to Python for production. In Aquarium, I have things setup so that it knows that it can reload Cheetah templates and modules that don't have any state when they've changed. I think this is a requirement in any framework.

> Aside: something similar is also found in web.py, but there it bothers me, because it's invoked from normal-looking Python code. E.g. foo["x"] and foo.x are equivalent, when foo is a "Storage" object. But this leaves me wondering, what does foo.keys mean?

I dislike that feature. Fortunately, you can turn it off in Cheetah. It's great for template writers and irritating for developers. You are quite astute: if you have a key named "keys", foo.keys isn't what you want ;)

> A big difference: if Django doesn't find a name, it inserts nothing; but Cheetah raises an exception.

This reminds me of how if you do $blah->{bar}->{bat}->{nonexistent}, you'll get a null in Perl. I really dislike that feature. Give me an exception anyday so that I can just fix my code.

As for escaping, you're right about Quixote. Fortunately, Mike Orr has been working on the same thing for Cheetah. I think that's the right direction that we need to go in.

> And even if they could be used for this, the verbosity of the XML syntax and the inability to do a proper if-then-else in XML make template writing using XML a non-starter.

Amen! When we switched from TAL (before my time) to Cheetah, all the programmers came by my cube and thanked me ;)

> All these have different APIs. But are the differences important?

Yes. Django templates are for designers. Cheetah templates are for Python programmers. I think both are good, and that this distinction in general is good.

> Perhaps we could attempt some standardization here similar to WSGI?

I think template syntax *is a matter of taste*.

One more plug for Cheetah, I've noticed that almost every major framework has support for it. Perhaps in response to this, Tavis Rudd has be *on fire* lately fixing everything in Cheetah that was even remotely questionable. Taste aside, Cheetah is mature and very high quality.

Guido van van Rossum

Posts: 359
Nickname: guido
Registered: Apr, 2003

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 1:01 PM
Reply to this message Reply
> I'm really surprised you haven't looked at Myghty

Can you guys stop being surprised that I haven't heard of every single one of the 80 or so frameworks available?

> (http://www.myghty.org/). Myghty is a port of the
> extremely popular Perl templating system HTML::Mason used
> by major websites like del.icio.us, Amazon.com, and many
> many more.

And why would being a port of something in Perl be a good thing? Most Python modules that were ported from another language's popular API (e.g. threading.py, unittest.py, and the whole XML DOM thing) suffer from some amount of braindamage due to not being sufficiently Pythonic.

Apart from the admitted prejudice, I looked at the example in the next post, and both the templating language and the API look horrible to me. What's the advantage of using ARGS['name'] instead of $name? Why do they call files/streams buffers? Why is the output stream declared when the interpreter is created? Why do I need an interpreter object (apart from remembering the output stream, which seems too-early binding anyway)? I could go on; every aspect of it either looks Perlish or smells like a dinosaur.

> The templating solution it provides is far more powerful
> than any of the others I've seen, and allows for
> sophisticated caching when speed is a concern.

I'm not sure that more templating power is really needed; and all the contenders are extensible so by definition you can have all the power you need.

> Regarding a standard, there is sort of a standard
> developing, that TurboGears has pioneered, and Pylons also
> supports. It's called template plug-ins:
> http://www.turbogears.com/docs/plugins/template.html

Thanks for the pointer! Perhaps it is right -- if other frameworks support the same interface to templating plugins, then only one plugin (really a kind of adaptor) needs to be written for each templating package, and we can all be happy campers. Django designers, what do you think of this idea?

> You get a consistent interface to use a variety of
> template languages of your choice. If the Django templates
> can be used completely on their own, I'm not sure why they
> aren't supporting this developing standard.

They should. I hope they're listening!

Ben Bangert

Posts: 6
Nickname: bbangert
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 1:30 PM
Reply to this message Reply
> And why would being a port of something in Perl be a good
> thing? Most Python modules that were ported from another
> language's popular API (e.g. threading.py, unittest.py, and the
> whole XML DOM thing) suffer from some amount of braindamage
>due to not being sufficiently Pythonic.

Mainly because those of us coming to Python from Perl couldn't find anything as feature rich for templating as Mason was for Perl. Different people have different requirements for their templating language. There's plenty of cases when the flexibility afforded by powerful templating beats the purity of a template language devoid of the ability to put logic in it. You indicate that it's bad to put logic in the template, and indeed I wouldn't want any more than necessary, but I'm a fan of the "practical beats purity" approach.

> Apart from the admitted prejudice, I looked at the example in
> the next post, and both the templating language and the API
> look horrible to me. What's the advantage of using ARGS['name']
> instead of $name?

Isn't $name a Perl style for a variable? ARGS is a dict.... that's normal dict access. Myghty uses normal Python syntax in its templates (for the most part), so it should feel rather Pythonic.

> Why do they call files/streams buffers?

Because it's referring to web output, and the buffer holds data being prepared to be sent out to the web.

>> Why is the output stream declared when the interpreter is created? Why do I need an interpreter object (apart from remembering the output stream, which seems too-early binding anyway)? I could go on; every aspect of it either looks Perlish or smells like a dinosaur.

Honestly, this typically never comes up. If you use the Myghty template plug-in, you do the same as any other template plug-in, here's an example of such a usage (with Kid, but you could say Cheetah or Myghty with one word changing):

buffet = Buffet()
buffet.prepare('kid', '/some/path/to/templates')
myvars = dict(name="George", house="Elm St.")
buffet.render('kid', 'thetemplate.kid', myvars)


It's a simple interface, and this example was for my own Buffet (http://projects.dowski.com/projects/buffet) inspired class.

I've actually been looking for additional template languages, while Myghty meets my needs perfectly it does let you use normal Python (assuming you like Python syntax much :). This means you couldn't let an untrusted user make templates in it of course.

I'm still looking over the Django templates, if they are safe for un-trusted users and support the template plug-in stuff, there's definitely a place for Django templates in some of my webapps.

Tavis Rudd

Posts: 13
Nickname: tavis
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 1:38 PM
Reply to this message Reply
Hi Guido,
thanks for the note about 2.5 issues. I assume you are using Cheetah 1.0 as that's already fixed in 2.0. I haven't bothered fixing it in 1.0 as it's somewhat unlikely for someone to use 1.0 with Py 2.5a when Cheetah 2.0rc3 is available ;)

Most of the other points you raise are either due to misunderstandings (i.e. from bad explanations in our docs) or have been resolved in Cheetah 2.0.

I'll go through them point by point:

** Point 1:
"The biggest difference is that Cheetah allows pretty much arbitrary Python call syntax, e.g. ${foo.bar('hello', $name, 42+42)}."

Cheetah 2.0 provides a facility for selectively restricting both the Cheetah directives allowed and the Python/Cheetah expressions allowed. It allows you to take either a 'deny all then enable' or a 'selectively disable' approach. These restrictions occur at template compile time. It is not a rexec system.

** Point 2:
"you have to prefix variable references in the argument list with another $, and there are confusing rules about when the $ is optional."

The docs are confusing, the rules are not. We improving this in the 2.0 documentation. $ is only required when you are inserting a $placeholder into text at the top level. Inside a #directive or other expression, you only need a $ if you want to do a var lookup using the searchList. Note, the NameMapper/searchList stuff is completely optional and many people don't use it.

** Point 3:
"A big difference: if Django doesn't find a name, it inserts nothing; but Cheetah raises an exception. ISTM that Django is more user-friendly here, even if its approach could be considered error-prone (typos are easily missed since they simply suppress a small bit of output). In my experience, missing variables are very common in substitution data, and Cheetah requires you to provide explicit default values in this case."

First off, Cheetah 2.0 introduces a 'silent-mode' for placeholders which does exactly what you want:
$!doNothingIfNotFound vs. $raiseAnExceptionIfNotFound
This syntax is taken from Java's Velocity.

As other commenters have pointed out
> > Guido was wrong thinking that Cheetah always raises an
> > exception for unfound names. It is optional and
> > intentional (usefull if you want to catch any errors
> very
> > early).
>
> I read that before I posted, but they state very clearly
> that they don't want you to use this to provide default
> values for substitutions; they only want you to use it for
> debugging. Again, the recommended approach is wrong IMO
> and that counts more than what you can hack. Fighting the
> system should not be a standard behavior.

Most users of Cheetah would disagree with you here. You don't want errors from mistyped $placeholderNames to slip by silently. If you want to provide default values, use a default namespace in the searchList.

** Point 4:
"But then I stumbled upon Cheeta's inline form, which is pretty unreadable due to the symmetric delimiters:
# if $name # <h1>Hello $name</h1> # else # <h1>Hello There</h1> # end if #
"

In 2.0, you could have also used the following forms:

#if $name:<h1>Hello $name</h1>
#else: <h1>Hello There</h1>

OR

#if $name then c'<h1>Hello $name</h1>' else '<h1>Hello There</h1>'

c'<h1>Hello $name</h1>' is a special string syntax that allows you to use $placeholders inside of strings that are part of expressions.

** Point 5:
"See the examples near the top. I like Django's version better: you pass the variable bindings in to the render() method. Cheetah lets you specify multiple dictionaries with variable bindings, which are searched one after another, but it bothers me that these all have to be passed to the Template() constructor instead of to the render method (which is called __str__() in Cheetah :-)."

It also bothered me. 2.0 provides a new classmethod api (Template.compile) which returns a compiled template class. You then instantiate that class with a searchList (if you are using NameMapper,etc.). This is the new recommended usage style in 2.0 is to create a template class and reuse it many times:

tclass = Template.compile(src)

t1 = tclass() # or tclass(namespaces=[namespace,...])
t2 = tclass() # or tclass(namespaces=[namespace2,...])

outputStr = str(t1) # or outputStr = t1.aMethodYouDefined()

Template.compile provides a very flexible API via its optional arguments so there are many possible variations of this pattern. One example is:

tclass = Template.compile('hello $name from $caller', baseclass=dict)
print tclass(name='world', caller='me')

See the Template.compile() docstring for more details.

Template.compile() caches the compiled code in most cases, so if you call it in a tight loop with a src string that has already been compiled you won't be hit with the cost of recompiling for each iteration.

Furthermore, 2.0 allows you to pass the searchList into a specific method on the template. This post is already way to long, so I'll post an example later.

*** Point 6:
"Django's template compilation is much simpler and IMO more elegant than Cheetah: Django parses the template text into nodes of various types using a big regular expression, and each node has an appropriate render() method. Rendering the template in a given context simply concatenates the results of rendering each node in that context. I imagine this could easily be turned into a generator compatible with WSGI."

Guido, are you honestly saying that one big regex is more elegant than a recursive descent parser (even a slightly ugly hand-built one)? Cheetah, in its toddler phase, used a simple regex-based parser. It was a nightmare: brittle, limited, and hard to understand!

Cheetah's parser doesn't build an intermediate AST, which is arguably a failing but hasn't been an issue in practice. Anyway, if you want to critique the parser please look at the 2.0 version :)


*** Point 7:
"Cheetah, OTOH, compiles each template to a Python class! This is much slower, and in my experience brittle -- on my first attempt I introduced a syntax error in the template that caused a Python syntax error in the resulting Python class, which was hard to debug. It also seems overkill, and I worry that it might cause security problems"

You're missing a key usage issue here. Cheetah users do *not* compile their templates for every web request. The compile a template *once* and then a method is called on it for each request. Or if you use Template.compile() you can create a new template instance per request. Besides, the compilation is cached.

Regarding Python syntax errors slipping through, you've got a good point. As Cheetah can accept almost any Python syntax in its expressions I avoided implementing full parsing of the Python syntax for fear that I'd introduce more errors in the parsing than I'd prevent from slipping through. That said, we're moving towards full parsing of Python expressions.

Btw, the tracebacks in 2.0 are much easier to understand as Template.compile() allows you to keep the compiled module files in a cache dir which Python can then access during traceback formatting.

Compiling the templates to a Python class is regarded as Cheetah's greatest strength as it allows you to subclass templates in either Python or Cheetah. Vice versa, your templates can be subclasses of *any* Python class:

tclass = Template.compile('hello $name', baseclass=dict)
print tclass(name='Guido')


T1 = Template.compile(''' foo - $meth1 - bar
#def meth1: this is T1.meth1''')

T2 = T1.subclass('#implements meth1\n this is T2.meth1')

*** Point 8:
"I could see a malicious template author "breaking out" of the templating languages and invoking unauthorized Python code. Now, I wouldn't let people I don't trust edit templates on my website anyway, but it appears to be a common pattern that certain people are allowed to edit templates but not code. Cheetah blurs the distinction a little too much for my comfort."

Regarding security, see my note above about the expression/directive filtering in 2.0.


Thanks for checking it out!
Tavis

Tavis Rudd

Posts: 13
Nickname: tavis
Registered: Jan, 2006

Re: Django vs. Cheetah: 1-0 Posted: Jan 31, 2006 1:57 PM
Reply to this message Reply
btw, some of my examples in the last post used 'namespaces' where you'd be expecting 'searchList'. This is an alias we added in 2.0 and has exactly the same semantics.

p.s. excuse my typos ;)

Flat View: This topic has 86 replies on 6 pages [ « | 1  2  3  4  5  6 | » ]
Topic: Django vs. Cheetah: 1-0 Previous Topic   Next Topic Topic: ScalaTest 0.9 Released


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us