A Brief Django/TurboGears Comparison

by Jeremy Jones

Here are a few thoughts that I have now that I've completed porting my wife's website from TurboGears to Django. This isn't intended to be a comprehensive list of differences between TurboGears and Django. Nor is it intended to assert superiority of one framework over the other. These are simply my thoughts and feelings regarding the two frameworks. That being said, my conclusion is that Django is a better fit for me.

1. TurboGears has a little bit faster hit-the-ground-running startup time because it creates all the files you need with a single command without having to run subsequent commands to create the application. This is a definite tradeoff, though. Even though it's another command to create an app (within a project) in Django, the flexibility of being able to have multiple apps self-contained in their respective directories is, in my opinion, worth the extra step.

2. TurboGears' directory structure and file layout is simpler than Django's. Again, the number and location of files and directories in Django is a direct result of the flexibility of being able to have multiple applications in the same project. I don't mind the slightly deeper directory nesting or the few more files in a new Django project (and app).

3. The template system in Django took a little bit to get used to. One thing that tripped me up for a while was Django's variable substitution does dictionary and attribute lookups, method calls, and list indexes all using a dot. I expected to access a dictionary's key using some_dict["some_key"], but instead, it's some_dict.some_key. And I expected to access a method by some_object.some_method(), but instead, it's some_object.some_method. This was clearly my fault as it is obviously documented here After getting past that hitch, I really like Django's templating system. It's really simple but powerful enough to do anything you want to do. Since you can't just execute arbitrary code in a Django template, it forces you to pass in the data you need from your view. This separation is a good thing. Unquestionably, in my mind anyway, Kid is a very powerful templating system. However, the ability to execute pretty much any Python code you want to from within a Kid template is a little concerning. And the requirement of Kid documents being well-formed XML can be a bit of a pain. And when you create one that isn't well formed, you don't always get back an accurate error corresponding to your Kid template. For example, here are the first seven lines of a Kid template which I intentionally mangled (line numbers supplied from vim):


1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://w ww.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://purl.org/kid /ns#">
3
4 <head>
5 <title>${title}<title>
6 <link type="text/css" rel="stylesheet"
href="/static/css/ppp.css"/>
7 </head>


Notice the mismatched title tag on line 5. The error I received was ExpatError: mismatched tag: line 7, column 2. A tag name would be more helpful here. And an accurate line number corresponding to the Kid template would be helpful as well.

4. Which leads me to the errors you get back from Django templates. They are excellent. If I try to access a URL that isn't specified in the urls.py file, I get a nicely formatted error page with the contents of my urls.py file that helps me see the errors of my ways. And if I have a syntax error in my code, I get a traceback and source code with highlights of the offending code.

5. I've really come to appreciate Django's URL mapping approach. URL->function calls are explicitly declared in the urls.py file. This allows me to easily create URLS that look like I want them to look and not have to hang one class off of another to create the nested structure that I may want. It also lets me create RESTful looking URLS if I so wish. Another benefit is that you get (for free) a "table of contents" of your site all in one file. TurboGears is a little more awkward to fashion your URLs the way you want them. I did read the other day that there is a package that sounds like it allows CherryPy to use an alternative URL mapping scheme which sounds more like Django, but I haven't investigated that yet.

6. Django's admin interface is really slick. I haven't been able to use it as much as I would like because it doesn't appear to be able to display nested data structures on a single page. For example, if I have a Customer data object which can have multiple CustomerOrder (as in, the customer has ordered some merchandise) data objects and each CustomerOrder can have multiple OrderItem (as in, individual pieces of merchandise in the order) data objects, I haven't found a way to display the Customer related to the CustomerOrder related to the OrderItems all in the same page in the admin interface. The last time I looked at CatWalk in TurboGears, it seemed like it was a pretty slick database browser, but not really geared for turning end-users loose on.

11 Comments

RickCopeland
2006-02-10 12:42:48
Kid Errors

Notice the mismatched title tag on line 5. The error I received was ExpatError: mismatched tag: line 7, column 2. A tag name would be more helpful here.


Actually, I think I can explain this: Kid uses expat to parse the XML, and expat isn't a validating parser. That means that basically all it does is match beginning and ending tags. When expat sees the following tags:
<html> <title> <title> <link> </link> </head>
, the first time it knows that something is amiss is when it sees the </head>, since it's expecting </title>, and so it reports the error on line 7.


If Kid used a validating parser, it would have been able to tell that you can't put a "title" tag inside another "title" tag, and it would have failed on line 5, but using expat seems to have limited them a bit.


Not that it excuses the poor error handling on the part of Kid, but maybe at least it explains it. To avoid these problems, I generally use XML mode in emacs, which validates and indents the tags as I type.

jmjones
2006-02-10 18:39:45
Kid Errors
OK - I'll buy your explanation. That actually makes sense. I was really trying to come up with a simple example of Kid's error handling. I should have rather created something with a Python syntax error in it. I think those are even worse. But we're apparently agreed on the error reporting in Kid.


I typically use a vim XML plugin which creates the close tags for me, but doesn't validate. Doesn't sound as nice as your emacs plugin, but it's better than nothing.

tazzzzz
2006-02-10 21:18:30
Kid Errors
You're right about that being a shortcoming. I'm pretty confident we'll get that cleaned up at the sprint following PyCon.
sigzero
2006-02-11 08:29:54
They both need something...
Oracle support would be nice. Without it they are both dead to me. I will have to pick up Myghty, which is a very nice system for Python web application development in itself.
DougN
2006-02-11 13:25:41
You can easily have nested structures in DJango Admin
Look at the 'edit_inline' attribute which can be assigned to relationships:
http://www.djangoproject.com/documentation/model_api/


When you create a ManyToMany, OneToOne or a ManyToOne with ForeignKey, you add edit_inline=meta.TABULAR or edit_inline=meta.STACKED. This will tell the admin interface how to treat the inlining in the Parent model.


ManyToMany relationships also have 'filter_interface' which gives a selection group listing (this is how permissions are handled in the admin interface).


Example:
class Foo(meta.Model):
boo = meta.CharField(max=10, default="hi")
class META:
admin = meta.Admin()


class Bar(meta.Model):
bang = meta.ForeignKey(Foo,
edit_inline=meta.TABULAR,
num_in_admin=5,
num_extra_on_change=3)
data = meta.CharField(max=20, core=True)


## this will put a table at the botom of the Foo admin (and there will be no Bar admin), with 5 open edit fields for adding up to 5 Bar objects and there will be a minimum of 3 open slots after the first save. The 'core' tag of data is to denote that when this field is empty, delete that Bar row in its table. You can have multiple core objects, which means they must all be empty before the entry is removed.


Hope that helps!

DougN
2006-02-11 13:28:18
Oracle support comming soon
http://www.jrandolph.com/blog/?p=23
jmjones
2006-02-11 13:37:32
You can easily have nested structures in DJango Admin
I knew about this, but what I was referring to is, what if (in your example) there's a third class Bam which has a ForeignKey back to Bar? How do you have that third nested level in the admin interface? I either emailed the Django list or asked on IRC and got the reply that it's not really do-able. If it is possible, that would be awesome.
DougN
2006-02-12 09:27:16
You can easily have nested structures in DJango Admin
Sorry, I mis understood your issue.
Looking at the code, this would indeed be a bit tricky to get working, but not impossable. I will try to get this added to the sprint at pycon.
pdc
2006-02-13 03:43:20
Kid and XML well-formedness
For me the fact that Kid templates are XML is an advantage: I use an XML-savvy text editor, jEdit, so it can check for XML errors before I even try running them in my web app.
Anonymous Coward
2006-02-24 07:34:47
I'm curious. You have 3:3 ratio of positive and negative points, and no explanation of your conclusion. As a matter of style, consider arriving at one logically instead of simply stating it, or don't conclude anything if it's too early to do so. Don't get me wrong, I really appreciate your stirring the pot and wouldn't know Django exists without you.
Keep up good blogging and thanks!
Derek Anderson
2006-04-05 23:24:32
I generally code on PyDEV on Eclipse for TurboGears, Eclipse having a nice validating XML editor as well. I was tempted at first to use Django, which seemed more mature, but was lured away by SQLObject and it's MySQL support (Django was only PostgreSQL, which is cool, but not well represented in many datacenters) Of course, Dgango works perfectly at this point with MySQL, but, now I know TG...