About a blog, part III

December 9, 2008

In the final part of my "About a Blog" series, I want to take a closer look at Django and spend some time talking about what works and what doesn't. Taking the long view, Django is just another MVC-style web framework. (Django devs actually say their implementation should be called a Model-Template-Web system, but that's just semantics for the moment). Now, there is no shortage of MVC web frameworks out there, so why would you want to use Django?

Easy To Use

Don't underestimate the importance of being easy: the ability of a web framework to be learned quickly is a huge win. This is not to say that Django is simplistic—it's not—but just that it has good documentation to get you up and running and the conceptual model of the Django framework is relatively easy to get. Initial configuration is minimal, the number of dependencies are low and there are lots of batteries included. Zope, by contrast, is not so easy to pick up. Ruby on Rails is a little better, but it's still going to take you more time to get to the same place than it will in Django. I'm not a Java dev, but I've heard all the complaints about J2EE.

Batteries Included

I mentioned the fact that Django comes with lots of useful stuff included as a reason why it's easy to use, but it's also an inherent advantage. You don't have to roll your own administration interface, ORM, caching, user comments, internationalization, form handling, or syndication. You don't have to use what Django gives you and you can customize these features to varying extents if you wish, but having them out of the box is nice.

Python

If Python is not your language of choice, well, that's cool. But if you're using, for example, PHP to build web sites, you're really missing out. Even with a decent MVC framework, like Symphony or CakePHP (both of which I've used), you're still missing out. I don't want to rehash all of PHP's problems or get into a static-vs-dynamic language debate with other language users (ahem, *Java*) , so I'll leave it at this: the more code I write, the more I'm convinced that LOC is a good heuristic for how maintainable and bug-free your codebase will be. Django let's you do more with less code, and that's a big win in my book.

Miscellaneous

Django has an active community and good documentation, both important in any decision to make a long-term investment in a web framework.


So, I talked about what's good. What's bad about Django? As I mentioned, Django is a great framework for building a CMS and in fact, that is what it was designed to do. So what happens when you try to build something that is nothing like a CMS? Could you create Basecamp, Twitter or Facebook with it? Does Django work for big enterprise-y applications?

I don't know. My hunch is that the answer is yes for most web 2.0/social networking sites out there. The devil is in the details, of course, but I think someone could build a Delicious clone, for example, pretty fast. In fact, given that Delicious is built with Symphony (PHP), I'd bet you could build the same app with less code.

I do have some concerns about how well Django would work outside it's original problem domain (e.g. CMS). All abstractions are leaky abstractions and few more so than ORM. This ground is already well traveled thanks to Rails and ActiveRecord, and if anything, Django's ORM is more simplistic. For complex systems with complex and well-normalized data, you might be better off with SQL Alchemy, but that doesn't necessarily discount Django. And realistically speaking, there will always be projects that will baffle even the best-designed ORM, but I think the proportion of people worrying and complaining about that possibility on the web far exceeds the number of people who actually experience it.

The other area where Django may not scale to other problems is the Administration interface. It is somewhat flexible, but I could see situations (a site with thousands of admin users, for example, or a site with a very complex admin interface) where it might break down. That said, the admin interface is not part of Django, proper, and you aren't required to use it: you can always write your own, which is what most frameworks leave you to do anyway.

So what are we left with: does Django scale to your problem domain or not? Well, your mileage may vary, but a good heuristic would be this: try modeling your data structure in Django, then try querying that model to see if you can get the data back out in the way that you need it. This doesn't require you to build a fully-functional Django application and will quickly tell you if Django's ORM is sufficient for your needs.

So far, the "negatives" I've mentioned aren't necessarily negatives, but really just caveats about Django not being all things for all projects. There are two specific complaints I have about Django, however.

URL Routing

URL Routing is done via regular expressions. If you come from an apache background and have experience with mod_rewrite, this will not be a big deal. But it's actually a clunky approach. Far better is the way Zope and RoR do it: they treat URLs as paths in an object hierarchy. So, for example, http://site/controller/action/id would map the request to the action method on a controller class, passing the id as a parameter to that method.

Views

In Django, as I mentioned, you use regex-based url matching to associate urls with views. Views are functions which are called with an HTTP Request and values passed along by the url matcher as arguments. They are required to return an HTTP Response object. Simple enough...in fact, too simple.

As you might guess, they break Django's DRY mantra because you have lots of views which are doing similar things, but have no way to share code. Fortunately, there are two possible solutions here.

You could use decorators to add shared functionality, but this is a limiting approach in that you can only wrap other view functions. If you have a some code that cross-cuts anything that happens in your shared code, then decorators won't work.

The second, better solution is to use a class as a view. Remember, in Python, functions aren't the only things that are callable. Any object that implements a __call__ method can act like a function. And classes allow you to have inheritance, which allows you to reuse code. In fact, Django actually does this in it's internals, and it's a much better approach. You get all kinds of ancillary benefits as well, like static methods, which allow you to implement breadcrumbs very easily. Here's the base view class I use in my blog from which all views inherit:


from os import path


from django.http import HttpResponse, HttpResponseNotFound
from django.shortcuts import render_to_response

class BaseView(object):
    
    template = None
    projectNamespace = None
    context = None
    response = None
    
    def __new__(klass, request, *args, **kwargs):
        obj = super(BaseView, klass).__new__(klass)
        return obj(request, *args, **kwargs)
    
    def __call__(self, request, *args, **kwargs):
        self.update(request, *args, **kwargs)
        self.request = request
        self.render()
        return self.response
    
    def update(self, request, *args, **kwargs):
        raise NotImplementedError, "This method is an abstract one; it should be defined in a child class." 
    
    def render(self):
        if (self.context and self.template):
            templatePath = path.join(self.projectNamespace, self.template)
            self.response = render_to_response(templatePath, self.context)
        else:
            self.response = HttpResponseNotFound

If you ever used Zope3, you'll recognize the update() and render() methods I borrowed, which are called to create the context of the view (the V in MVC) and then create an HTTP response by calling a template against the view's context, respectively. The C in MVC can be implemented as methods called by update().

I have some other minor quibbles with Django, but I've covered the main points. If you want to read some other valid complaints which have not (yet) been a problem for me, check out Jeff Croft's post Top ten things that suck about Django, revisited.

Tagged with: , , .

Leave a comment:

Comments are closed for this entry.