Apache with mod_python currently is the most robust setup for using Django on a production server. mod_python (http://www.djangoproject.com/r/mod_python/) is an Apache plug-in that embeds Python within Apache and loads Python code into memory when the server starts. Code stays in memory throughout the life of an Apache process, which leads to significant performance gains over other server arrangements. Django requires Apache 2.x and mod_python 3.x, and we prefer Apache’s prefork MPM, as opposed to the worker MPM.
Note – Configuring Apache is well beyond the scope of this book, so we’ll simply mention details as needed. Luckily, a number of great resources are available if you need to learn more about Apache. A few of them we like are as follows:
- The free online Apache documentation, available via http://www.djangoproject.com/r/apache/docs/
- Pro Apache, Third Edition (Apress, 2004) by Peter Wainwright, available via http://www.djangoproject.com/r/books/pro-apache/
- Apache: The Definitive Guide, Third Edition (O’Reilly, 2002) by Ben Laurie and Peter Laurie, available via http://www.djangoproject.com/r/books/apache-pra/
Basic Configuration – To configure Django with mod_python, first make sure you have Apache installed with the mod_python module activated. This usually means having a LoadModule directive in your Apache configuration file. It will look something like this:
LoadModule python_module /usr/lib/apache2/modules/mod_python.so
Then, edit your Apache configuration file and add the following:
<Location “/”>
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
Make sure to replace mysite.settings with the appropriate DJANGO_SETTINGS_MODULE for your site. This tells Apache, “Use mod_python for any URL at or under ‘/’, using the Django mod_python handler.” It passes the value of DJANGO_SETTINGS_MODULE so mod_python knows which settings to use. Note that we’re using the <Location> directive, not the <Directory> directive. The latter is used for pointing at places on your filesystem, whereas <Location> points at places in the URL structure of a Web site. <Directory> would be meaningless here.
Apache likely runs as a different user than your normal login and may have a different path and sys.path. You may need to tell mod_python how to find your project and Django itself.
PythonPath “[‘/path/to/project’, ‘/path/to/django’] + sys.path”
You can also add directives such as PythonAutoReload Off for performance. Note that you should set PythonDebug Off on a production server. If you leave PythonDebug On, your users will see ugly (and revealing) Python tracebacks if something goes wrong within mod_python. Restart Apache, and any request to your site (or virtual host if you’ve put this directive inside a <VirtualHost> block) will be served by Django.
Note – If you deploy Django at a subdirectory — that is, somewhere deeper than “/” — Django won’t trim the URL prefix off of your URLpatterns. So if your Apache config looks like this:
<Location “/mysite/”>
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
then all your URL patterns will need to start with “/mysite/”. For this reason we usually recommend deploying Django at the root of your domain or virtual host. Alternatively, you can simply shift your URL configuration down one level by using a shim URLconf:
urlpatterns = patterns(”,
(r’^mysite/’, include(‘normal.root.urls’)),
)
Running Multiple Django Installations on the Same Apache Instance – It’s entirely possible to run multiple Django installations on the same Apache instance. You might want to do this if you’re an independent Web developer with multiple clients but only a single server. To accomplish this, just use VirtualHost like so:
NameVirtualHost *
<VirtualHost *>
ServerName www.example.com
# …
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</VirtualHost>
<VirtualHost *>
ServerName www2.example.com
# …
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
</VirtualHost>
If you need to put two Django installations within the same VirtualHost, you’ll need to take a special precaution to ensure mod_python’s code cache doesn’t mess things up. Use the PythonInterpreter directive to give different <Location> directives separate interpreters:
<VirtualHost *>
ServerName www.example.com
# …
<Location “/something”>
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonInterpreter mysite
</Location>
<Location “/otherthing”>
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
PythonInterpreter mysite_other
</Location>
</VirtualHost>
The values of PythonInterpreter don’t really matter, as long as they’re different between the two Location blocks.
Running a Development Server with mod_python – Because mod_python caches loaded Python code, when deploying Django sites on mod_python you’ll need to restart Apache each time you make changes to your code. This can be a hassle, so here’s a quick trick to avoid it: just add MaxRequestsPerChild 1 to your config file to force Apache to reload everything for each request. But don’t do that on a production server, or we’ll revoke your Django privileges.
If you’re the type of programmer who debugs using scattered print statements (we are), note that print statements have no effect in mod_python; they don’t appear in the Apache log, as you might expect. If you have the need to print debugging information in a mod_python setup, you’ll probably want to use Python’s standard logging package. More information is available at http://docs.python.org/lib/module-logging.html. Alternatively, you can or add the debugging information to the template of your page.
Serving Django and Media Files from the Same Apache Instance – Django should not be used to serve media files itself; leave that job to whichever Web server you choose. We recommend using a separate Web server (i.e., one that’s not also running Django) for serving media. If, however, you have no option but to serve media files on the same Apache VirtualHost as Django, here’s how you can turn off mod_python for a particular part of the site:
<Location “/media/”>
SetHandler None
</Location>
Change Location to the root URL of your media files. You can also use <LocationMatch> to match a regular expression. For example, this sets up Django at the site root but explicitly disables Django for the media subdirectory and any URL that ends with .jpg, .gif, or .png:
<Location “/”>
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>
<Location “/media/”>
SetHandler None
</Location>
<LocationMatch “\.(jpg|gif|png)$”>
SetHandler None
</LocationMatch>
In all of these cases, you’ll need to set the DocumentRoot directive so Apache knows where to find your static files.
Error Handling – When you use Apache/mod_python, errors will be caught by Django — in other words, they won’t propagate to the Apache level and won’t appear in the Apache error_log.
The exception to this is if something is really messed up in your Django setup. In that case, you’ll see an “Internal Server Error” page in your browser and the full Python traceback in your Apache error_log file. The error_log traceback is spread over multiple lines. (Yes, this is ugly and rather hard to read, but it’s how mod_python does things.)
Handling a Segmentation Fault – Sometimes, Apache segfaults when you install Django. When this happens, it’s almost always one of two causes mostly unrelated to Django itself:
It may be that your Python code is importing the pyexpat module (used for XML parsing), which may conflict with the version embedded in Apache..
It may be because you’re running mod_python and mod_php in the same Apache instance, with MySQL as your database back-end. In some cases, this causes a known mod_python issue due to version conflicts in PHP and the Python MySQL back-end.
If you continue to have problems setting up mod_python, a good thing to do is get a bare-bones mod_python site working, without the Django framework. This is an easy way to isolate mod_python-specific problems. The article “Getting mod_python Working” details this procedure: http://www.djangoproject.com/r/articles/getting-modpython-working/.
The next step should be to edit your test code and add an import of any Django-specific code you’re using — your views, your models, your URLconf, your RSS configuration, and so forth. Put these imports in your test handler function and access your test URL in a browser. If this causes a crash, you’ve confirmed it’s the importing of Django code that causes the problem. Gradually reduce the set of imports until it stops crashing, so as to find the specific module that causes the problem. Drop down further into modules and look into their imports as necessary. For more help, system tools like ldconfig on Linux, otool on Mac OS, and ListDLLs (from SysInternals) on Windows can help you identify shared dependencies and possible version conflicts.