django & appengine

Last night I went to j4amie‘s brightonpy talk Python and Django for PHP Refugees (slides). It was a really good talk, though I knew most of the Python stuff. The django intro was great however.

What I was really interested in was using Django together with appengine. I’ve used appengine before with the builtin webapp framework. Whilst it’s good, it’s simplistic and I found myself building layers on top quickly.

Looking through the docs, the first thing I see is Running Django on Google App Engine. But this says that the builtin django is obsolete and I should be using django-nonrel. There is further documentation on this, Running Pure Django Projects on Google App Engine. This approach is interesting. It’s encouraging you to not be appengine specific, the way that you are with webapp’s default setup.

django-nonrel is made up of several components; you should start by looking at djangoappengine. You’ll need to download all five components.

You’ll also need the appengine SDK in case you don’t have it.

Once you’ve downloaded everything, import the necessary bits into a project you made with the appengine SDK.

% pwd
/Users/dom/work
% cp -r $APPENGINE_SDK/new_project_template hellodjango
% cd hellodjango
% mv ~/Downloads/wkornewald-django-nonrel-c73e6ca3843d/django .
% mv ~/Downloads/wkornewald-djangotoolbox-f79fecb60e6d/djangotoolbox .
% mv ~/Downloads/wkornewald-django-dbindexer-48589f5faad4/dbindexer . 
% mv ~/Downloads/wkornewald-djangoappengine-f9175cf4c8bd djangoappengine
% ls -l
total 24
-rwxr-x---@  1 dom  5000   106 13 Apr 12:09 app.yaml*
drwxr-xr-x@ 12 dom  5000   408 13 Apr 12:43 dbindexer/
drwxr-xr-x@ 18 dom  5000   612 13 Apr 12:33 django/
drwxr-xr-x@ 23 dom  5000   782 13 Apr 12:43 djangoappengine/
drwxr-xr-x@ 15 dom  5000   510 13 Apr 12:43 djangotoolbox/
-rwxr-x---   1 dom  5000   472 24 Mar 23:38 index.yaml*
-rwxr-x---   1 dom  5000  1002 24 Mar 23:38 main.py*

You’ll have to bundle all of this with your app. You may want to delete some bits of django/contrib that you don’t use.

Now, how to get started with my app? I’ll need to create a django project. Normally I use the installed django-admin.py. In this case, I’d like to use the version I’ve imported to my project.

% PYTHONPATH=. django/bin/django-admin.py 
Usage: django-admin.py subcommand [options] [args]% PYTHONPATH=. django/bin/django-admin.py startproject hellodjango
% mv hellodjango/* .
%

So now how do I hook that up to app.yaml? There’s no documentation, but there is a test app. And that contains the magic snippet:

handlers:
- url: /.*
  script: djangoappengine/main/main.py

Now, how do I run this? The appengine launcher I’m using has a “play” button. My first attempt broke, because I’d made the app in the hellodjango directory, the settings contained a reference to hellodjango.urls, which should be just urls. With that fixed, I get an “It worked!” page. Result!

The dev_appserver.py approach (aka the play button) worked for me, but the djangoappengine docs say to use ./manage.py runserver, so I’ll do that.

Now, I have an empty app. Let’s add in a minimal hello world view. First, I create views.py

from django.http import HttpResponse
 
def home(request):
  return HttpResponse('<h1>Hello World</h1>')

And then adjust urls.py to point to it.

from django.conf.urls.defaults import patterns, include, url
 
import views
 
urlpatterns = patterns('',
  url(r'^$', views.home, name='home'),
)

I now see the Hello World! displayed in my browser. I’d like to get a nice template working. I’ll update my views to look like this:

from django.shortcuts import render
 
def home(request):
  return render(request, 'home.html')

templates/home.html is as you would expect.

<h1>Hello World!</h1>

The final piece of the puzzle: how does django know where to find the template? In settings.py, there’s a TEMPLATE_DIRS setting.

TEMPLATE_DIRS = (
  os.path.join(os.path.dirname(__file__), 'templates'),
)

At this point, you’re using regular django, and should be able to use the regular docs to carry on. Although, please read the list of djangoappengine caveats.