Hi all,

I've recently been exploring simple multitenancy options in Django
using contrib.sites, and have some thoughts on how core could make it
easier.

First, let me make a quick distinction between static and dynamic
multitenancy. In the static case, you have a limited set of sites
running on the codebase, that set changes infrequently, and it's not a
problem to have separate settings files for each (which probably
requires some level of additional webserver configuration for each as
well). Django already supports this form just fine via contrib.sites
and the SITE_ID setting.

In dynamic multitenancy, the set of tenant sites changes often and
should be manageable via the database with no need for additional
configuration files or webserver reloads. In order to do this
currently using contrib.sites, you have to stuff the request object
into threadlocals and then monkeypatch contrib.sites to get the
hostname from the threadlocals request and return a Site object
accordingly. (This is the approach taken by Satchmo's django-threaded-
multihost [1] and its fork django-multihost [2]). Having to do this
makes me sad.

But there's good news! Thanks to the work of Gabriel Hurley and others
in r13980 [3], contrib.sites now sports a get_current_site() function
that takes the request as a parameter, and this function is used
throughout Django! Having access to the request gives us most of what
we need; all that's lacking is a way for a project to put in place an
alternative policy such as "return a Site object based on matching
request.get_host() to Site.domain, rather than using
settings.SITE_ID". (This is distinct from the current fallback to
RequestSite if contrib.sites is not installed. RequestSite uses
request.get_host(), but doesn't care what its value is, and doesn't
get a corresponding Site object from the database, so it doesn't let
you name the sites or limit the set of valid domains.)

A few options for how such a hook could be implemented:

1) A setting, something like
SITES_CURRENT_SITE="path.to.my.alternative.get_current_site_function".
This is quite flexible, but Yet Another Setting.

1a) Same as above, but reuse SITE_ID; i.e. it can either be an
integer, or a string path to a get_current_site function. It ends up a
bit misnamed.

2) get_current_site fires a signal first thing, and listeners can
return a Site object to short-circuit the default behavior. This is
also fully flexible, but seems like perhaps more than is necessary.

3) get_current_site checks the request for a "site" attribute, and
returns that if it exists. This allows the project to define its own
site-selection logic in a middleware, and just attach the chosen Site
object to the request. The issue here, I guess, could be backwards-
compatibility with people who may already be annotating their requests
with a "site" attribute. I'm not sure what guarantees Django offers in
terms of not encroaching on namespaces which aren't specifically
documented as open for user annotation, but I know annotating requests
is not uncommon.

Any thoughts on which option should be preferred here? Is there an
even better option I've overlooked?

Thanks,

Carl

  [1] http://bitbucket.org/bkroeze/django-threaded-multihost
  [2] https://github.com/jaddison/django-multihost
  [3] http://code.djangoproject.com/changeset/13980

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to