Using virtualenv with Django on WebFaction

Today I set up a site on WebFaction’s hosting for the first time. Initially it was lovely — the control panel makes it easy to set up a wide arrange of different kinds of hosting environments. I got pip and virtualenv working fine, but I wasn’t sure how to have the site run within a virtualenv.

(Having written all of that, I’m not sure if it’s ideal… why have I set up an application of type ‘django’ when I want to use my own particular copy of Django within my virtualenv? Maybe I should try and follow these instructions for doing this with a ‘mod_wsgi’ application, even though that seems a little more complicated? (28 June 2011))

I found a couple of sets of instructions, although neither seemed to use the ‘django’ application type as described in WebFaction’s ‘Getting Started with Django’ guide.

After much trial and error, here’s the solution I came up with. Any suggestions for improvements are very welcome as I’m sure this could be better.

This guide assumes you’ve probably used pip and virtualenv/virtualenvwrapper before and just want to get it working on WebFaction. You’ve followed the ‘Getting Started with Django’ guide, which will have created:

/home/username/webapps/django_application/myproject/
/home/username/webapps/django_application/myproject.wsgi

Then:

$ easy_install virtualenv
$ easy_install pip
$ pip install virtualenvwrapper
$ mkdir ~/.virtualenvs
$ vim ~/.bashrc

Add these lines at the end of .bashrc:

export WORKON_HOME=$HOME/.virtualenvs
source /home/username/bin/virtualenvwrapper.sh
export PIP_VIRTUALENV_BASE=$WORKON_HOME # Tell pip to create its virtualenvs in $WORKON_HOME.
export PIP_RESPECT_VIRTUALENV=true # Tell pip to automatically use the currently active virtualenv.

Then:

$ source ~/.bashrc
$ mkvirtualenv --no-site-packages --distribute my_env_name

Obviously, with a meaningful name instead of ‘my_env_name’. Now we’re working within that virtual environment. Note: The version of Python that your virtualenv uses by default may be different from the one your Django app is set to use. You can make it use a specific version by adding something like ‘-p python2.6’, e.g.:

$ mkvirtualenv --no-site-packages --distribute -p python2.6 my_env_name

Assuming that version of Python installed on your system. (Type “python” and then tab a couple of times to see the options.)

Install any things you need. eg:

(my_env_name)$ pip install yolk

Or install from a pip requirements file from an existing project:

(my_env_name)$ pip install -r REQUIREMENTS.txt

Then, the bit that took me ages to work out, edit ~/webapps/django_application/myproject.wsgi. I don’t know if all of these are required, but it seems to work for me…

import os, sys, site

# Tell wsgi to add the Python site-packages to its path. 
site.addsitedir('/home/username/.virtualenvs/my_env_name/lib/python2.6/site-packages')

os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'

activate_this = os.path.expanduser("~/.virtualenvs/my_env_name/bin/activate_this.py")
execfile(activate_this, dict(__file__=activate_this))

# Calculate the path based on the location of the WSGI script
project = '/home/username/webapps/django_application/myproject/'
workspace = os.path.dirname(project)
sys.path.append(workspace)

from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()

Obviously, replace ‘username’, ‘my_env_name’, ‘django_application’ and ‘myproject’ as appropriate.

Finally:

(my_env_name)$ cd ~/webapps/django_application/myproject/
(my_env_name)$ python manage.py syncdb
(my_env_name)$ ../apache2/bin/restart

You’ll need to do that last line every time you make a change to myproject.wsgi.

Cron

Getting a Django manage.py command to run via cron seemed tricky. The best way seems to be to make a bash script to run what you want. Something like this:

#! /bin/bash

source $HOME/.virtualenvs/my_env_name/bin/activate

$HOME/webapps/django_application/myproject/manage.py commandname

Obviously, replace ‘commandname’ with whatever command you want to run. And you can have multiple lines of that. Then type ‘crontab -e’ to edit the cron file and add something like:

15 * * * * $HOME/cron.sh > $HOME/cron.log 2>&1

Where you can replace cron.sh with the path and filename to wherever your bash script is. Everything from the > onwards tells it to send output to a log file of your specifying. Omit that if you like.

Comments

  • Sorry about my english:
    My log is:

    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] connection = connections[DEFAULT_DB_ALIAS]
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] File “/home/cemap/webapps/geofoc_django/lib/python2.7/django/db/utils.py”, line 93, in __getitem__
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] backend = load_backend(db[‘ENGINE’])
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] File “/home/cemap/webapps/geofoc_django/lib/python2.7/django/db/utils.py”, line 33, in load_backend
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] return import_module(‘.base’, backend_name)
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] File “/home/cemap/webapps/geofoc_django/lib/python2.7/django/utils/importlib.py”, line 35, in import_module
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] __import__(name)
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] File “/home/cemap/webapps/geofoc_django/lib/python2.7/django/db/backends/postgresql_psycopg2/base.py”, line 9, in
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] from django.db import utils
    [Sun Dec 11 18:08:16 2011] [error] [client 127.0.0.1] TemplateSyntaxError: Caught ImportError while rendering: cannot import name utils

    Many Thanks

27 Jun 2011 at Twitter

  • 11:21am: What’s the point of being freelance if you can’t stay home and take it easy occasionally?
  • 12:42pm: A moment for friend’s survey? @AnnieFeighery: Which sectors r family-friendly for an emerging global health researcher? http://bit.ly/mKhywv
  • 01:06pm: London/urbanism geeks! This Sunday at RFH, “Rebuilding the City: 1951 and now”: http://bit.ly/iwRJeX (I can’t make it, booo.)
  • 01:21pm: @AnnieFeighery Pleasure! I hope it’s useful :)
  • 04:41pm: @blech I’m not sure the City of London (for one part of this city) would officially endorse that quote, unfortunately.
  • 04:48pm: @blech There’s plenty of time left to move to Berlin (or anywhere else) some day!
  • 04:52pm: Double “long, sweaty afternoon of first time Webfaction Django WSGI server configuration success” fist punch!
  • 05:29pm: @mildlydiverting It’s very, erm, “specialist”.
  • 10:08pm: A slid open door / concrete / a still warm still, still night / @mattsheret’s last.fm radio / typing.

27 Jun 2011 in Writing

The undercover quanitifed self
A chunk of Hamish MacGibbon’s father’s life was recorded by the security services, and still readable fifty years later.

27 Jun 2011 in Links

On this day I was reading