Today I deployed my first Django application for a client. Its yet-another-blog, so I’ll refrain from posting the code and cluttering up the django-*blog* namespace on Google Code. Before you roll your eyes and complain about why I didn’t use an existing solution, I think I have 2 somewhat valid reasons:
- The client actually needed a _sub_set of the features most blogs offer, so I wouldn’t really have anything to contribute back to an existing project.
- Blogs are one of the simplest content driven web applications in existence. Wikis are just a bit simpler perhaps. At any rate, creating a blog app is an excellent way to learn a framework.
Python Deployment Decisions
In the past I’ve used CherryPy as my framework and a simple mod_proxy configuration to run the applications behind Apache. Django considers its built-in web server a development tool only, so I figured it was time to explore the myriad of Python web app deployment alternatives: mod_python, FastCGI, modwsgi. I’m sure there are many more, but I’d say those are the big 3.
I had tried to deploy Python web applications on DreamHost using FastCGI before and entered the hell that is deploying Python web apps on shared hosts. So FastCGI wasn’t my first choice this time.
Deploying a Django App via modwsgi
modwsgi was quite easy to setup as long as you follow the instructions in their wiki for Django integration. I was hit by bug #3762, but the modwsgi documentation got me through it. (For what its worth the attached wsgi.patch also worked, but I don’t really want to run a patched version of Django.)
One big problem I ran into was sqlite3 gave me
OperationalError: unable to open database file whenever I did anything that would write to the database. My database file was owned by
www-data (the Apache process owner) and had the permissions
My wsgi script file /srv/spam/eggs/eggs.wsgi:
import os, sys sys.path.append('/srv/spam') sys.path.append('/srv/spam/eggs') os.environ['DJANGO_SETTINGS_MODULE'] = 'eggs.wsgi_settings' import django.core.handlers.wsgi _application = django.core.handlers.wsgi.WSGIHandler() def application(environ, start_response): environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO'] return _application(environ, start_response)
Note I use
wsgi_settings instead of my usual settings file. wsgi_settings just imports my main settings file and changes some to their production values.
My Django application actually drops into the
/accounts/ folders under a VirtualHost otherwise occupied by static files and some PHP scripts. modwsgi made this easy by putting this in my existing VirtualHost:
WSGIScriptAliasMatch /(blog|accounts)/.* /srv/spam/eggs/eggs.wsgi # A simple Alias directive handles my static files Alias /static/ /srv/spam/eggs/static/
I highly recommend using modwsgi for deploying Python web applications. sqlite3 may work for you. In my case its probably best I use PostgreSQL for a number of reasons.