Django deployment with virtualenv pip and fabric

There was an interesting discussion recently  on HackerNews around different Django deployment options. The original author was asking about choices of server (apache, uwsgi, gunicorn etc). The consensus seemed to be Nginx in front of Apache. Many people, myself included, also chimed in with other deployment advice, such as using fabric to push your code to the server, and pip to manage dependencies.

I've been using fabric for deployment for a while, but only recently started using Virtualenv and pip. There are lots of good posts on the benefits of using these tools, and how to start using them:

When I decided to start using virtualenv and pip I created the following fabric task to install some required system packages, create a virtualenv, and then install the python packages:
def new_virtualenv():
    with cd(env.path):
        sudo("apt-get -q -y install gcc python-setuptools python-all-dev libpq-dev libjpeg-dev")
        sudo("easy_install pip virtualenv")
        sudo("virtualenv --no-site-packages virt-python", user="www-data")
        sudo("pip -E virt-python install -r requirements.txt", user="www-data")

This works for new development machines too. All I need to do is check out the code from git, and then run that task to setup the virtualenv and all required packages. I'd like to be able to to set up a whole server from scratch automatically, and although fabric would get me a lot of the way when I've got a bit more time I'm going to look into using littlechef for this.

Now that I'm using virtualenv and pip my standard fabric deploy task has an additional step, which is to install any new dependencies via pip. Here's the complete task, which runs unit tests, checks out the latest code, performs any required database migrations, installs any new requirements, and then touches the wsgi file to get apache to reload the project:

def update():
    local("./ validate")
    local("./ test core")
    with cd(env.path):
        sudo("git pull origin master", user="www-data")
        sudo("./ migrate --all", user="www-data")
        sudo("pip -E virt-python install -r requirements.txt", user="www-data")
        sudo("touch apache/django.wsgi", user="www-data")

I initially had problems getting apache's mod_wsgi to use the virtualenv, but managed to solve it by using Graham Dumpleton's improved wsgi script.

Posted on 31 Oct 2010
If you enjoyed reading this post you might want to follow @coderholic on twitter or browse though the full blog archive.