How to run Django under Paste Deploy for locally testing a WSGI pipeline

Django can be run under any WSGI server, which means you can use it in a WSGI pipeline. Deploying Django under mod_wsgi is well documented, but sometimes you want to test your WSGI pipeline on a local server without mucking with configuring nginx or apache, and/or try out some WSGI development tools that you don't want to accidentally put on your production config.

Paste Deploy is a nice little WSGI server that we can use for this purpose, but I didn't find any existing tutorials for running Django under it, hence this post.

First, you'll need a python file that defines a WSGI application for your Django app. This can be the same as you would use for deploying under mod_wsgi; so, see the docs for that. Here's mine:

import os
import sys
import site

os.environ['DJANGO_SETTINGS_MODULE'] = 'foo.settings'
os.environ['PYTHON_EGG_CACHE'] = '/tmp/foo-python-eggs'

# I use VirtualEnv a lot; need to get its site-packages onto the path.
env_root = '/home/pw/hacking/foo-environ'

#####################################################################
# End of configurable stuff. Below shouldn't need to be edited.

# Some libraries (eg. geopy) have an annoying habit of printing to stdout,
# which is a no-no under mod_wsgi.
# Workaround as per http://code.google.com/p/modwsgi/wiki/ApplicationIssues
sys.stdout = sys.stderr

sitepackages_root = os.path.join(env_root, 'lib')
for d in os.listdir(sitepackages_root):
    if d.startswith('python'):
        site.addsitedir(
            os.path.join(sitepackages_root, d, 'site-packages')
        )
        break
else:
    raise RuntimeError(
        "Could not find any site-packages to add in %r" % env_root
    )

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

You'll need to add one more thing to that file: an app_factory function as per the Paste Deploy docs:

def app_factory(global_config, **local_conf):
    return application

Now, to test this, write a minimal development.ini file:

[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 8000

[app:main]
paste.app_factory = mypackage.my_wsgi_module:app_factory

That configures the paste server and loads your Django app as the main application.

Now try firing things up:

$ paster serve development.ini
Starting server in PID 4898.
serving on http://127.0.0.1:8000

Browse to http://localhost:8000 and make sure it works.

Middleware

There's a couple ways we could add middleware.

For middleware that is necessary to the application, I'm going to assume that we will be deploying under mod_wsgi, and so the middleware can be set up by manually wrapping the application object in our python WSGI script. That way it'll be used both in production and development regardless of what WSGI server we use.

But for development purposes, sometimes you want to use some middleware that isn't appropriate to a production deployment. For that, it's probably more sane to edit our development.ini file.

As an example, let's try some profiling with the dev version of Dozer, as suggested by http://mg.pov.lt/blog/profiling-with-dozer. Let's install it:

$ pip install -e hg+http://bitbucket.org/bbangert/dozer#egg=Dozer

Now let's configure it as a filter in development.ini:

[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 8000

[pipeline:main]
pipeline = dozer django

[app:django]
paste.app_factory = mypackage.my_wsgi_module:app_factory

[filter:dozer]
use = egg:Dozer#profile
profile_path = /tmp/profiles

Re-start the dev server and check out Dozer's profiling at http://localhost:8000/_profiler/showall