What is the best solution for multi tenancy in Django?
There's several things you're asking here. 1: how to model relationships between models, 2: how to display a view for a single companyFor problem one, Django handles problems like this in data modeling with relationships. Here's the documentation tutorial for relationships: https://docs.djangoproject.com/en/dev/topics/db/models/#relationships
In your example, a Property to Company relationship is 'many-to-one', meaning that a Company has many Properties but a Property has only one Company. In Django(the link I gave you) all that is typically done is a foreign key in the model that is the 'many', or in your case Property. Here's what I would do:
class Property(models.Model):
owner = models.ForeignKey(Company)
This also allows you to query relationships, solving the second problem.If I have a Company c
, I can access all the Properties associated with it like this:
c.property_set.all()
# => [Property <MyProperty>, Property <OtherProperty>, ...]
That's a query you would do in the view and then pass to the template.Here's a Django-provided example of this very thing(many-to-one) that you may find useful: https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/.
optimal architecture for multitenant application on django
We built a multitenancy platform using the following architecture. I hope you can find some useful hints.
- Each tenant gets sub-domain (t1.example.com)
- Using url rewriting the requests for the Django application are rewritten to something like example.com/t1
- All url definitions are prefixed with something like
(r'^(?P<tenant_id>[\w\-]+)
- A middleware processes and consumes the tenant_id and adds it to the request (e.g. request.tenant = 't1')
- Now you have the current tenant available in each view without specifying the tenant_id argument every view
- In some cases you don't have the request available. I solved this issue by binding the tenant_id to the current thread (similar to the current language using
threading.local
) - Create decorators (e.g a tenant aware
login_required
), middlewares or factories to protect views and select the right models - Regarding to the databases I used two different scenarios:
- Setup multiple databases and configure a routing according to current tenant. I used this first but switched to one database after about one year. The reasons were the following:
- We didn't need a high secure solution to separate the data
- The different tenants used almost all the same models
- We had to manage a lot of databases (and didn't built an easy update/migration process)
- Use one database with some simple mapping tables for i.e. users and different models. To add additional and tenant specific model fields we use model inheritance.
- Setup multiple databases and configure a routing according to current tenant. I used this first but switched to one database after about one year. The reasons were the following:
- Nginx
- uWSGI
- PostgreSQL
- Memcached
Pro:
- One application instance knowing the current tenant
- Most parts of the project don't have to bother with tenant specific issues
- Easy solution for sharing entities between all tenants (e.g. messages)
- One quite large database
- Some very similar tables due to the model inheritance
- Not secured on the database layer
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) the tenant_id
out of the request with something like request.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 ...%}
or reverse()
) or external apps.
Suggestion for Approachs to Develop Multi tenant Django Proj on Google App Engine
Today Google released SDK 1.3.6, which includes multi-tenancy baked right into the solution.
http://googleappengine.blogspot.com/2010/08/multi-tenancy-support-high-performance_17.html
Related Topics
Representing and Solving a Maze Given an Image
Scipy Curve_Fit Doesn't Like Math Module
Get the String Within Brackets in Python
In Python, Why Is List[] Automatically Global
Building a Minimal Plugin Architecture in Python
How to Test a Function with Input Call
Pandas: Subindexing Dataframes: Copies VS Views
Python - Requests.Exceptions.Sslerror - Dh Key Too Small
Broken References in Virtualenvs
Binary Numpy Array to List of Integers
First Python List Index Greater Than X
Is There a Numpy Builtin to Reject Outliers from a List
How to Print a Dictionary Line by Line in Python
Where Do the Python Unit Tests Go
How to Modify Procfile to Run Gunicorn Process in a Non-Standard Folder on Heroku
Looping from 1 to Infinity in Python