I needed a way to alter settings at runtime, based on the current
Site.  The method I came up with appears to work, but certainly
doesn't feel elegant and (I'm sure) could use improvement.  I'm going
to share my reasoning behind dynamic settings in the hopes that it
sparks some discussion about how this could best be achieved, and
possibly included, with Django.  At the very least I hope for feedback
from more experienced Python veterans :)

-- The Why --

Our internal CMS uses the Sites framework to relate all content to a
particular client website.  All clients share the same database and
most of the same settings.  An example of a client's settings file
looks like this:

from cms.conf.global_settings import *
SITE_ID = 35
TEMPLATE_DIRS = ['/www/example.com/templates/']
MEDIA_ROOT = '/www/example.com/media/'

This setup requires a Python settings file, a WSGI config file and an
Apache Virtual Host for each Site, which is silly because the *only*
difference between sites is the three settings above.  Multiple static
files have worked satisfactory thus far, but becomes a maintenance
problem as the number of sites increase.  Furthermore, it doesn't seem
very DRY because most of the configuration gets duplicated for each
Site.

In order to eliminate the need for a settings file for each site, I
began investigating using middleware to detect the current Site (based
on request.get_host()) and dynamically alter SITE_ID, MEDIA_ROOT and
TEMPLATE_DIRS.  I need to set SITE_ID because the rest of our CMS uses
the CurrentSiteManager to perform lookups (which behind the scenes
uses settings.SITE_ID).

-- My interim solution --

My approach was partly inspired by a Django snippet[1] and partly by
Threaded Multihost[2], a component that Satchmo uses to support
multiple Sites.

Here's a quick paste of the code: http://dpaste.com/hold/95266/

Again, I know it's ugly and needs massive improvement (by someone
smarter than me).  But here's how it works:

1) Middleware looks up the current Site based on domain, and sets two
variables, "request" and "site", on the thread.

2) The ThreadSetting class provides a descriptor to use in your
settings files to mark settings that may be altered at runtime.  This
lets you do things like provide a function that gets called to
determine the value for a given setting at any point in execution.
The descriptor allows this to happen without breaking the
"settings.FOO" syntax.  Callbacks get passed _thread_locals (which
will include the "request" and "site" from middleware).  Lastly,
LazySetting's getattr/setattr is monkey-patched to allow access to
these descriptors.

3) In settings.py you use ThreadSetting to specify which settings can
be altered, along with the function that should be used to calculate
the setting value whenever it's requested.  You can see in my example
how it's used to set SITE_ID and TEMPLATE_DIRS.

As far as I can tell, in order to use the Sites framework to build a
[near] zero configuration application *without* breaking
CurrentSiteManager or Site.objects.get_current(), settings.SITE_ID
will need to be set at runtime based on the request's hostname.
Additionally, this needs to be done in such a way that multiple
threads are not simultaneously modifying the same setting (thus the
use of thread locals).

I expect using the Sites framework to create "instant-on" domains and
subdomains from a single Django application is a common use-case,
especially for hosted web applications.  It would be *awesome* if
Django somehow accommodated this use-case.

I'm very interested in hearing other's thoughts on the subject.  I
would love a way to do this in a Django-approved fashion, without
having to monkey-patch LazySettings.

Thanks,
Kyle.


[1] http://www.djangosnippets.org/snippets/1099/
[2] http://gosatchmo.com/apps/django-threaded-multihost/
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to