= How to use django with mod_wsgi = This is a very simple recipe to deploy a django application with mod_wsgi. This procedure has been tested on Windows but should work on any operating system supported by apache, mod_wsgi, and django. == Installation == The mod_wsgi package can be downloaded from http://code.google.com/p/modwsgi/. Ensure that you work through the mod_wsgi [http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide installation] and [http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide configuration] instructions before trying to setup Django. For links to Windows binaries and steps on setting up mod_wsgi Windows see its separate [http://code.google.com/p/modwsgi/wiki/InstallationOnWindows installation] instructions but still refer to main installation instructions to work out if mod_wsgi was installed correctly. If wanting to know about source code reloading issues when running Django under Apache and mod_wsgi then ensure you read document about [http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode reloading] on mod_wsgi site. Do be aware that reloading your application by touching the WSGI script file only works for mod_wsgi daemon mode on UNIX/Apache 2.X systems. That specific reloading feature is not available on Windows, Apache 1.3 or if using embedded mode with Apache 2.X. If mod_wsgi daemon mode is available, you can also set it up to automatically restart on any code change. This is covered in mod_wsgi documentation on reloading, but is made clearer in [http://blog.dscpl.com.au/2008/12/using-modwsgi-when-developing-django.html this blog entry]. This will give you same sort of automatic reloading capability as the Django development server. Be aware that on UNIX systems you have the choice of using mod_wsgi in embedded mode or daemon mode. If you are not adept at configuring Apache and do not know how to tune Apache MPM settings to suit a specific type of application, then make sure you use mod_wsgi daemon mode. This is because the default Apache MPM settings are for static file serving and PHP, they are not suitable for large persistent Python web applications. If you use embedded mode and don't change the settings you are likely to have problems with running out of memory on memory constrained systems and see load spikes which may cripple your system. These are the same problems that can arise as when using mod_python and you similarly haven't tuned the Apache MPM settings. You will need to delve into the documentation on the mod_wsgi site for how to use daemon mode. Note that the mod_wsgi site provides its own documentation for [http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango integrating Django with mod_wsgi]. Those instructions go into areas this document does not and in some respect should be seen as being a more definitive source of information. It is also a good idea to read through other documentation on the mod_wsgi site as well, especially in respect to installation, configuration or application issues. Reading the other documentation on the mod_wsgi site will save you a lot of time if you do have any issues as it is quite comprehensive. == Configuration of Apache and mod_wsgi == In this section I will take you through an example, the django application is called dj_survey. This application is part of a project called "dj_project". The {{{urls.py}}} I used to serve the application with the Django built-in development server: {{{ #!python from django.conf.urls.defaults import * import registration urlpatterns = patterns('', # Example: # (r'^dj_project/', include('dj_project.foo.urls')), # Uncomment this for admin: (r'^admin/', include('django.contrib.admin.urls')), (r'^dj_survey/', include('dj_project.dj_survey.urls')), (r'^accounts/', include('registration.urls')), (r'^yui/(?P.*)$', 'django.views.static.serve', {'document_root': '../../svn_views/yui/build','show_indexes': True}), (r'^site_media/(?P.*)$', 'django.views.static.serve',{'document_root': './media','show_indexes': True}), ) }}} In {{{httpd.conf}}} you should load the mod_wsgi and include the file containing the configuration of your django application. The trap there is all the path should use "/" and not "\". === httpd.conf === {{{ #This should be included somewhere at the top of this file LoadModule wsgi_module modules/mod_wsgi.so #somewhere at the bottom Include "/apache/apache_django_wsgi.conf" }}} '''NOTE: Putting settings file in the 'apache' subdirectory where the WSGI script file is located is technically a security risk. This is because in order for the WSGI script file to be served from there, you have had to configure Apache to tell it it can use that directory. In doing that, it can technically serve files from there as static files. Thus, if Apache was incorrectly configured and files in that directory made accessible via a URL as static files, it would be possible to download the settings file. Since the settings file can contain database passwords, that obviously isn't going to be a good thing to happen. This example really should be modified, with settings files located one directory up from where they are, as would normally be the case.''' This suppose that you have created a folder named {{{apache}}} in your django project in this folder your should add the following files: {{{ 08/16/2007 04:12 PM 1,082 apache_django_wsgi.conf 08/16/2007 04:31 PM 557 dj_survey.wsgi 08/16/2007 04:31 PM 4,362 settings_production.py 08/16/2007 04:09 PM 712 urls_production.py 08/16/2007 04:33 PM 0 __init__.py }}} __Note__: There is a file called {{{__init__.py}}} in {{{/apache}}}. In this case {{{}}} is equal to {{{c:\\workspace\dj_project}}} Like in the {{{httpd.conf}}} you should pay attention to the separator. You should use "/" and not "\" === apache_django_wsgi.conf === {{{ Alias /site_media/ "/media/" /media"> Order allow,deny Options Indexes Allow from all IndexOptions FancyIndexing Alias /yui/ "/build/" /build"> Order allow,deny Options Indexes Allow from all IndexOptions FancyIndexing Alias /media/ "/trunk/django/contrib/admin/media/" /trunk/django/contrib/admin/media"> Order allow,deny Options Indexes Allow from all IndexOptions FancyIndexing WSGIScriptAlias / "/apache/dj_survey.wsgi" /apache"> Allow from all }}} Now here it is the core of the wsgi application. The path there should use "\\"as separator. === dj_survey.wsgi === {{{ #!python import os, sys #Calculate the path based on the location of the WSGI script. apache_configuration= os.path.dirname(__file__) project = os.path.dirname(apache_configuration) workspace = os.path.dirname(project) sys.path.append(workspace) #Add the path to 3rd party django application and to django itself. sys.path.append('C:\\yml\\_myScript_\\dj_things\\web_development\\svn_views\\django_src\\trunk') sys.path.append('C:\\yml\\_myScript_\\dj_things\\web_development\\svn_views\\django-registration') os.environ['DJANGO_SETTINGS_MODULE'] = 'dj_project.apache.settings_production' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler() }}} __Note__: If you need to write something in {{{error.log}}} located in the following folder {{{\Apache2.2\logs}}} you can insert the line below in your WSGI file. In our example this file is called {{{dj_survey.wsgi}}}. This method is very convenient to get the PYTHONPATH correct: {{{ #!python print >> sys.stderr, sys.path }}} In this file you are defining the settings that will be used by your Django application, in our example this file is called: {{{dj_project.apache.settings_production}}} (__Note__: ".py" is implicit and should not be added). There is nothing special in that file except that I am pointing to a special {{{urls.py}}} which reflect the configuration I am using in production. {{{ #!python ROOT_URLCONF = 'dj_project.apache.urls_production' }}} === urls_production.py === {{{ #!python from django.conf.urls.defaults import * import registration urlpatterns = patterns('', # Example: # (r'^dj_project/', include('dj_project.foo.urls')), # Uncomment this for admin: (r'^admin/', include('django.contrib.admin.urls')), (r'^dj_survey/', include('dj_project.dj_survey.urls')), (r'^accounts/', include('registration.urls')), ) }}} == Test == Restart apache and now you should be able to enjoy your application served by Apache and mod_wsgi. === Additional Tweaking === If you're taking advantage of the great Internationalization features of Django you may come across a curious problem. Namely, uploading of non-ascii filenames with the Django storage system with the default apache settings on most systems will trigger UnicodeEncodeError exceptions when calling functions like os.path(). To avoid these issues, ensure that the following lines are included in your apache envvars file (typically found in /etc/apache2/envvars). {{{ export LANG='en_US.UTF-8' export LC_ALL='en_US.UTF-8' }}} This error likely wont rear its head during development on the test server as, when run from the command line, the ./manage.py script inherits the users language and locale settings. == References == * http://code.google.com/p/modwsgi/ * http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango * http://code.google.com/[http://www.repairpartstock.com/products-big-list.asp?id=577 cellphone parts wholesale]IntegrationWithDjango