I’ve been working with Python and Django lately, here’s my configuration for future reference

The setup

I’ve got a test website built with Django and it’s running on a VPS (at Linode). the setup is as follow

  • Ubuntu 8.04 LTS with the Apache preform MPM package
  • python virtualenv
  • Django
  • mod_wsgi 2.4

Some explanation on the setup

As I plan to have many website on this server, I want to be able to use different version of some libraries (I don’t always have the time to update every website for each new Django release). That’s why I use Virtualenv

My setup use apache prefork because of php.net recommend it (and Passenger needs it, keep an open door for Sinatra) and mod_wsgi in deamon mode (wsgi 2.4 (branches/wsgi-2.x) from svn because of the backport addsitedir())

Setting up virtualenv

python virtualenv.py --no-site-packages pythonenv
cd pythonenv
source bin/activate

from there, path have been changed to user this virtualenv, I can install django the usual way

easy_install django 

(type deactivate to return to your standard path, read more about virtualenv)

Setting up django

Once your virtualenv is activated, you can build your Django apps the usual way

Installing mod_wsgi

mod_wsgi >= 2.4 is needed, because of the backporting from 3.0 of the reodering of the path afet a call to addsitedir()

As of today, 2.3 is the stable release, so we’ll fetch 2.4 from svn:

svn co http://modwsgi.googlecode.com/svn/branches/mod_wsgi-2.X mod_wsgi-2.x
cd !$
.configure
make
sudo make install

On my Ubuntu 8.04, the apache configuration was done automatically (you may have to run a2enmod mod-wsgi).

Setting up the Apache config for mod_wsgi

I’ll assume here that you know how to use virtual host. Next step is to create the config for mod_wsgi

in /etc/apache2/sites-available/django-test

<VirtualHost *>
    ServerName example.com

    Alias /static/ /path/to/my/django/project/static/

    # I'm new to mod_wsgi
    # throw a lot of output so I can debut and learn what's happening
    LogLevel info

    WSGIDaemonProcess example.com display-name=%{GROUP}
    WSGIProcessGroup example.com
    WSGIScriptAlias / /path/to/your/django/project/application.wsgi

    <Directory /path/to/my/django/project>
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>

Some explanation on the settings

  • WSGIDaemonProcess: mod_wsgi default to embeded mode, which give you more performance, but have the downside that you need to restart apache when you want to reload your application to apply changes. Using this directive will switch it to Daemon mode (with it, you can reload your application by touching your application.wsgi
    • display-name is used to show a different name when you run ps, will show the groupname as {wsgi:example.com}
    • there’s a lot of other parameters that you can give, like threads=15, or process=2. go read the doc if needed
  • WSGIScriptAlias: the first / tell mod_wsgi to take care of every requested url that start with a slash, and use the applications.wsgi to handle it

Testing the apache/mod_wsgi setup

Just to test that your mod_wsgi is working with this config, create an application.wsgi file in your django project folder (were not involving django for now)

def application(environ, start_response):
    start_response('200 OK', [('content-Type', 'text/html')])
    return ['Hello World']

You may now restart apache (sudo apache2ctl restart (or graceful)) an nagigate the virtual host with your browser, you should see Hello World. If not, you can check the apache log file

/var/log/apache2/error.log

Setting up Django to act as a wsgi application

If everything is working, you may now create a wsgi application for your django project. Replace the file named application.wsgi in you Django project folder with the following content:

import os
import sys
import site
 
# One directory above the project, so project name will be needed for imports
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 
# with mod_wsgi >= 2.4, this line will add this path in front of the python path
site.addsitedir(os.path.join(root_dir, 'lib/python2.5/site-packages'))
 
# add this django project
sys.path.append(root_dir)
 
os.environ['DJANGO_SETTINGS_MODULE'] = 'subyt.settings'
 
import django.core.handlers.wsgi
 
application = django.core.handlers.wsgi.WSGIHandler()

The important line here is the ‘site.addsitedir’ one. That set your virtualenv path at the top of the python path, so your library are used before those of the main python install

Setting up a web.py project with mod_wsgi

Sometime I have some simple page/apps where that would be overkill to use Django, so I also use web.py. It’s almost the same setup, but instead of calling this in your webpy-app-file.py

application = web.application(urls, globals())

just call this

application = web.application(urls, globals()).wsgifunc()

Now point you WSGIScriptAlias to this file and voila! Please note that if your using web.py with virtualenv, you’ll have to add the site.addsitedir() as in the Django example

update 2009-04-01: if you’re not using virtualenv (which I don’t recommend), you can follow some easier instructions, as Django documentation now recommend mod_wsgi for deployment

3 thoughts on “Django, virtualenv and mod_wsgi

  1. Just a note, to build mod_wsgi, you need the python-dev and the apache2-prefork-dev packages. Otherwise you get nasty errors on ./configure and make. So far, that’s the only problem I’ve run into. Thanks for the tutorial, Eric!

  2. Pingback: Setting development environment in Ubuntu ( django, mod_wsgi, apache2, virtualenv) | Random Thoughts of a Technology Enthusiast

  3. Pingback: Reviewboard, PIL and virtualenv | Chen Yufei's blog

Comments are closed.