I'm trying to get mod_wsgi working with Django (1.0), and I've hit a
problem that I can't seem to be able to solve. It's simple enough that
I'm sure the solution is obvious and I'm just being stupid, but I've not
been able to find anything that works, even after several hours
searching and trying alternatives :-( Any help for a struggling
mod_wsgi newbie would be much appreciated!
The situation is: I have a simple app. It works in Django's test
server, and is meant to serve from three base URLs - let's call them
/admin, /foo, and /bar. My url.py therefore looks something like this:
-----------------------------------------------
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
(r'^foo/', another.handler),
(r'^bar/', yet.another.handler)
)
-----------------------------------------------
In the dev server, these are available as /admin, /foo, and /bar.
Now, for production, I want Apache to be serving the root (for example,
the static pages located at /d, /e and /f) but I want /admin, /foo, and
/bar to go to Django via mod_wsgi. After some experimentation, and
after reference to the documentation [1] I hit upon this Apache config:
-----------------------------------------------
WSGIScriptAlias /admin /path/to/my/wsgifile/config.wsgi
WSGIScriptAlias /foo /path/to/my/wsgifile/config.wsgi
WSGIScriptAlias /bar /path/to/my/wsgifile/config.wsgi
<Directory /path/to/my/wsgifile/>
Order deny,allow
Allow from all
</Directory>
-----------------------------------------------
The problem with this is that although access to /admin, /foo and /bar
was being delegated to Django correctly, the URL that was passed to
Django had the /admin (or whatever) stripped off - so its URL matching
did not work. So, I tried using some code from the documentation to add
it back in - in config.wsgi, I put (with mysite.settings and the
sys.path.append changed, of course):
-----------------------------------------------
import os, sys
sys.path.append('/usr/local/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()
def application(environ, start_response):
environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
return _application(environ, start_response)
-----------------------------------------------
I was unsure about this, as it looked like it was for versions of Django
prior to 1.0, and anyway seemed to be a workaround for a now-fixed
Django bug - but it seemed to work, until I tried to log in using
Django's admin interface, under /admin. When I did that, the login page
appeared correctly, but logging in tried to redirect me to
/admin/admin/admin. After looking at a few other examples, my best
guess is that pages that did redirects were somehow appending an extra
copy of the SCRIPT_NAME at the start of the URL.
I'm not sure what to make of all this but I guess my modified
config.wsgi is completely wrong...
Is that correct? And if so, what is the right way to configure mod_wsgi
so that it handles these "root-level" URLs but also passes them down to
the Django URL resolver?
Any help would be much appreciated!
Cheers,
Giles
[1] http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
--
Giles Thomas
MD & CTO, Resolver Systems Ltd.
giles....@resolversystems.com
+44 (0) 20 7253 6372
Try out Resolver One! <http://www.resolversystems.com/get-it/>
17a Clerkenwell Road, London EC1M 5RD, UK
VAT No.: GB 893 5643 79
Registered in England and Wales as company number 5467329.
Registered address: 843 Finchley Road, London NW11 8NA, UK
2008/10/28 Giles Thomas <giles....@resolversystems.com>:
Add within this Directory block:
WSGIApplicationGroup myapp
This will force all URLs to be handled within same Python sub
interpreter within the process. Without it, each WSGIScriptAlias mount
point would see a separate Python sub interpreter created for that
subset of URLs.
If this is the only Python web application you are running via
mod_wsgi, probably better to make it the main Python interpreter by
using:
WSGIApplicationGroup %{GLOBAL}
> Order deny,allow
> Allow from all
> </Directory>
> -----------------------------------------------
>
> The problem with this is that although access to /admin, /foo and /bar
> was being delegated to Django correctly, the URL that was passed to
> Django had the /admin (or whatever) stripped off - so its URL matching
> did not work. So, I tried using some code from the documentation to add
> it back in - in config.wsgi, I put (with mysite.settings and the
> sys.path.append changed, of course):
>
> -----------------------------------------------
> import os, sys
> sys.path.append('/usr/local/django')
> os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
>
> import django.core.handlers.wsgi
>
> _application = django.core.handlers.wsgi.WSGIHandler()
>
> def application(environ, start_response):
> environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
> return _application(environ, start_response)
Close but not quite. You need to wipe out value of SCRIPT_NAME. Try:
def application(environ, start_response):
environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
environ['SCRIPT_NAME'] = ''
return _application(environ, start_response)
If you are using Django 1.0, this should be enough to make it happy.
> -----------------------------------------------
>
> I was unsure about this, as it looked like it was for versions of Django
> prior to 1.0, and anyway seemed to be a workaround for a now-fixed
> Django bug - but it seemed to work, until I tried to log in using
> Django's admin interface, under /admin. When I did that, the login page
> appeared correctly, but logging in tried to redirect me to
> /admin/admin/admin. After looking at a few other examples, my best
> guess is that pages that did redirects were somehow appending an extra
> copy of the SCRIPT_NAME at the start of the URL.
>
> I'm not sure what to make of all this but I guess my modified
> config.wsgi is completely wrong...
>
> Is that correct? And if so, what is the right way to configure mod_wsgi
> so that it handles these "root-level" URLs but also passes them down to
> the Django URL resolver?
>
> Any help would be much appreciated!
This is actually a hard one in some ways. Normal use case would be to
have root handled by Python web application, but then overlay other
URLs against static resources etc. Here you only want Python web
application to appear to be root, but not really, as only want to
expose specific URLs.
There may actually be other ways of doing this but would need to think
about. It might be able to be done using mod_rewrite rules in a tricky
way, but that could be more trouble than its worth and may still
require a fiddle in the WSGI script file.
If I come up with a way that doesn't require the fiddle in the WSGI
script file will let you know.
Graham
Not sure what you have in mind for what will be in the Location
directives. The mod_wsgi package doesn't generally rely on Location
directives for mapping URLs to an application, ie., in the style of
mod_python, as that approach has various problems.
Care to elaborate? May help me to come up with a better way of doing
it that doesn't involve a fiddle in the WSGI script file.
Graham
More later when validate the solution. :-)
Graham
2008/10/28 Graham Dumpleton <graham.d...@gmail.com>:
WSGIScriptAliasMatch ^/(admin|foo|bar)(/.*)?$
/Users/grahamd/Sites/echo.wsgi/$1$2
You do not need to make any changes to the WSGI script file. Just use:
import os, sys
sys.path.append('/usr/local/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
You don't need the WSGIApplicationGroup either as when using
WSGIScriptAliasMatch like this, the mount point is the non varying
part of the pattern on LHS. Ie., will correctly be seen as root of web
server for all three.