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.