I've been brooding over the right/optimal way to create a multitenancy application based on Django.
Some explanation:
Application can be used by several tenants (tenant1, tenant2, ...,).
All tenant-individual data has to be secured against access of other tenants (and their users).
Optionally tenants can create additional custom-fields for application-objects.
Of course, underlying hardware limits number of tenants on one "system".
1) Separating each tenant by e.g. sub-domain and using tenant-specific databases in the underlying layer
2) Using some tenant-ID in the model to separate the tenant-data in the database
I am thinking about deployment-processes, performance of the system-parts (web-server(s), database-server(s), working-node(s),...)
What would be the best setup ? Where are the pro's and con's?
What do you think?
I recommend taking a look at https://github.com/bcarneiro/django-tenant-schemas. It will solve your problems a bit like Reto mentioned, except that it uses postgresql schemas.
We built a multitenancy platform using the following architecture. I hope you can find some useful hints.
(r'^(?P<tenant_id>[\w\-]+)
threading.local
)login_required
), middlewares or factories to protect views and select the right modelsRegarding the environment we use the following setup:
From my point of view this setup has the following pro's and con's:
Pro:
Contra:
Of course the best architecture strongly depends on your requirements as number of tenants, the delta of your models, security requirements and so on.
Update: As we reviewed our architecture, I suggest to not rewrite the URL as indicated in point 2-3. I think a better solutions is to put the
tenant_id
as a Request Header and extract (point 4) thetenant_id
out of the request with something likerequest.META.get('TENANT_ID', None)
. This way you get neutral URLs and it's much easier to use Django built-in functions (e.g.{% url ...%}
orreverse()
) or external apps.Here are some pointers to related discussions:
mezzanine.utils.sites.current_site_id
,mezzanine.core.models.SiteRelated
andmezzanine.core.request