Ben Godfrey

All posts tagged “django”

Django, Drupal, Webmachine: Different frameworks for different projects

Django is an awesome framework but different projects have different needs. The last 2 projects I’ve been involved with have been using Drupal. Other projects I’m planning call for very RESTful designs. Webmachine, an Erlang framework, is a great fit for these.

I do still very much love Python and Django, perhaps even more that I’m using PHP day to day. I miss the REPL. I miss first class functions. I miss Django’s very tidy organisation of code.

Drupal is something I’ve studiously avoided for a long time, thinking it to be a Zope-like mire. That’s true to an extent: there are many versions and a lot of code. Drupal apps do have good separation of concerns. The internal organisation of modules and themes is useful, although there’s a little bit too much function name magic going on (“Why isn’t my validator firing? Who knows!”). I’m interested in hooks, although I haven’t needed them yet. The same concept has served Django hackers well.

Leaky abstractions

Django and Drupal are both leaky abstractions. It’s easy to create great big joins with Django’s ORM. Drupal generates a mammoth set of CSS and JS imports per page. Both of these can be addressed with programmer discipline, but sometimes it’s nice to have a thinner level of abstraction to make you think carefully about each requirement and how best to implement it. Webmachine is such an abstraction. What it does provide, however, is system management built on top of Erlang and OTP. People doing scale (a group I’m not a member of) find that writing the initial app is easy, scaling it is hard.

Easy hacking, easy scaling

Newer frameworks seek to make initial implementation easy and scaling easy too. Webmachine is undoubtedly somewhat harder to code for than Django, there are less batteries included, but, in theory at least, scaling is easier. Only a little of that is due to implementation, most is due to architectural style. Webmachine does get in your way a bit less when hacking RESTfully. Django does things like setting cookies on every hit, making caching harder, increasing load on your app.

I think the current leader for easy hacking, easy scaling is Google App Engine. The core of Django runs happily, the system scales to Google’s infrastructure, deployment is very simple. GAE has one flaw though, porting to another platform involves work modifying code and extracting data. While the code scales effortlessly, scaling a business around that code seems harder. If your goals don’t chime with Google’s, you’re stuck. Frameworks running on open source software stacks are more trustable and it’s for this reason that EC2 is so much more popular than GAE to date.

Announcing aftnn.org version 2.0

Version 2.0 of aftnn.org is here!

The new site is powered by the Byteflow with a few some custom bits. Byteflow runs on top of Django.

Some of the features I’m happiest about:

  • My FriendFeed collects all the stuff I’ve been doing on the web and I re-use that feed here.
  • The vast majority of old urls still work. My nginx config contains a rewrite line for each blog post. Not pretty, but fast.
  • The Content and Photos sections are dynamically generated, making them easier to maintain.
  • I can finally write blog posts in Markdown, not raw HTML. Byteflow actually allows me to select a text renderer per-post, so I can write one post in Markdown, the next in MediaWiki markup.
  • Comments are hosted locally again, not by Intense Debate, and are protected by CAPTCHA. Alternatively, you can log in with your OpenID to comment.
  • nginx serves up static content very quickly and gzips everything too.

There are always some down-sides though.

  • Blanket is gone. It was a resource hog and I didn’t want to port it to Python. Sorry.
  • Byteflow and Django don’t play as nicely with caches as I would like. Byteflow doesn’t provide Last-Modified, Expires or ETag headers for it’s pages. Django sets cookies immediately, instead of when a session is actually used, so it’s page are effectively uncacheable. Also, Django does not provide Content-Length headers for responses. All this degrades the performance of my site.
  • The Intense Debate comment import process lost the threading. I’ll try to fix the relevant posts by hand some time.

I hope you like the new site. Please post a comment if you find a bug or have any other feedback.

Nginx+Django+FastCGI

A lot of people seem to have posts like this, but there were some things that I got stuck on when moving to Nginx from Apache.

location ^~

The ^~ match can not be used with regular expressions.

This will not work as expected:

location ^~ /(foo|bar)/ {
    ...
}

Use the ~ match operator if you want to use an RE. Make sure that your RE matches don’t clash with you plain string matches. The latter will be preferred in this event.

location + root

If you want to specify a different root within a location block, be mindful that the uri is unchanged.

For example, if you want to publish Django’s admin media, you might write something like this:

location ^~ /admin/media/ {
    root /usr/local/django/django/contrib/admin/media;
}

When a request comes in, Nginx will concatenate the root and the uri to find the file to server. With this config, it will try to serve /usr/local/django/django/contrib/admin/media/admin/media/css/base.css.

SCRIPT_NAME and PATH_INFO

Django uses PATH_INFO to match against urlpatterns. Nginx’s fastcgi_params include doesn’t set that. It does set SCRIPT_NAME. If both PATH_INFO and SCRIPT_NAME are set to $fastcgi_script_name, Django seems to get an empty path for all requests. Just set PATH_INFO!

Request buffering to file

Nginx buffers large requests to file before passing them to an upstream server. There is no option to stop this from happening. If you want to track the progress of request uploads, you will need to use the Upload Progress Module.