Reusable Django apps

Published March 27, 2007. Filed under: Django.

A little while back I released a couple of Django apps to the world, and I’ve got a couple more in the pipeline (whenever some more of my copious free time rolls around, I’ll finish them up and get them out the door as well), so I’ve been thinking a bit about best practices for making them as easily reusable as possible. And James Tauber has started up a mailing list for discussing a Django application repository (anyone who’s interested in that should join up and get the discussion going), where he’s posed some questions about that exact topic.

So here are my random initial thoughts and ideas on the matter.

Packaging

This seems to be the one lots of people get hung up on: what format should Django apps be distributed in? Eggs are an obvious choice, and easy_install has wonderful integration with the Cheese Shop, but there are some significant downsides to eggs which make me feel a little uncomfortable.

So far I’ve just been putting things into Subversion repositories hosted on Google Code and thinking about making tarballs when I want to have an “official” package, but I’d love to see a better solution. Right now I don’t know what the right answer is to this one.

Imports

The Django tutorial walks you through creating a project and then putting an app inside that project’s directory, and this seems to be a pretty common idiom. But for distributing a reusable app, I don’t think this can cut it. For one thing, any file in your app that needs to import from another is basically stuck doing relative imports (since you can’t rely on the project name), and relative imports are evil. And that really starts to hurt when you need to do things like import from models.py when you’re inside a views module which has multiple files in it — relative imports can’t “go up one directory” to the app root to find things.

I think the best solution here is for standalone apps to be written with the assumption that they’ll live directly on the Python path, and so can use absolute imports stemming off the app name; e.g., myapp/views.py should be able to assume that from myapp import models will work. This also makes life easier for the end user of the app, because it’s quite a bit simpler to use a single installed copy of the app in multiple projects.

Templates

So far, I’ve provided example templates with both of the apps I’ve released; the pattern I’ve been following is to create a templates directory in the app, and then a subdirectory named the same as the app which will hold its sample templates. This seems to be a pretty good way to handle it, because it meshes well with the app-directories template loader; this way, a user who wants to get up and running with a minimum of fuss can just edit the sample templates in-place (to match up with site-specific block structure and inheritance, if necessary) and have things just work after that. I’ve also been getting into the habit of having custom views assume the presence of the appname template directory, and look for their template in there; generic views already do this, so it ends up being a unified convention for where the app’s views will find their templates.

Figuring out inheritance and block structure is harder; every site is going to have its own way of doing that, and it seems like it’ll be impossible to have truly “generic” templates without getting everybody to agree on some conventions. If we go that route, I think it might be nice to run with an assumed base.html which all templates can inherit from to get the site’s basic HTML structure, but I’m not sure if there should be some conventions for block names (though standardizing on a few block names might not be a bad idea; content is one that seems to be used a lot, so it might be a good candidate for this).

One more useful convention for templates is probably to name tag libraries after the application they belong to, possibly using multi-word names (with underscores) for apps which provide multiple libraries (e.g., you might have just one library — myapp — or several: myapp_foo, myapp_bar, etc.). There have also been a couple proposals for changing how Django looks for tag libraries, so that it’d become possible to do things like {% load myapp.foo %}, and that might be something worth looking into since it’d make this much easier.

URLs

In an ideal world, a reusable application will use the permalink decorator when defining get_absolute_url for its models, and will use the url tag in any sample templates it provides; that will allow on-the-fly reconfiguration of URLs without having to touch code or templates. Unfortunately, both permalink and url still have a couple issues to be worked out (mostly with cases where more than one URL points at the same view function), so there may still be cases where get_absolute_url needs to be hard-coded. When that happens, the application developer needs to document it clearly so that users will know they need to use ABSOLUTE_URL_OVERRIDES.

Dependencies

Some of this goes back to packaging, because a package format which allows dependency specification is really the best way to go here, but that won’t cover everything. Required settings, in particular, need to be documented, along with their acceptable values, so that users know what they’ll need to add to their project settings to use the app. Until, and perhaps even after, we have a standard package format, it might be a good idea to provide some sort of conventional way to check for dependencies; I suggested checking for this in the app itself, and I may go back and work on that a bit to provide a generic dependency-checking mechanism.

What else?

I’m sure there are more things which need to be worked out, and I’m sure there are people much smarter than me who have good ideas for how to do it, so pipe up in the comments, or join James’ mailing list and discuss there (I’ll be cross-posting this to the list momentarily).