Snapshot of citusdata/django-multitenant: 823★, Python. Python/Django support for distributed multi-tenant databases like Postgres+Citus
Snapshot summary built from the project's own GitHub metadata — there's no written TopGit review yet. The page will update automatically when a full review is published.
WHY NO REVIEW YET
TopGit writes full reviews for the most-starred, most-requested repositories. This page is a snapshot until then — see the READ ME tab for the original README in full.
Python/Django support for distributed multi-tenant databases like Postgres+Citus
Enables easy scale-out by adding the tenant context to your queries, enabling the database (e.g. Citus) to efficiently route queries to the right database node.
There are architecures for building multi-tenant databases viz. Create one database per tenant, Create one schema per tenant and Have all tenants share the same table(s). This library is based on the 3rd design i.e Have all tenants share the same table(s), it assumes that all the tenant relates models/tables have a tenant_id column for representing a tenant.
The following link talks more about the trade-offs on when and how to choose the right architecture for your multi-tenant database:
The following blogpost is a good starting point to start to use django-multitenant
https://www.citusdata.com/blog/2023/05/09/evolving-django-multitenant-to-build-scalable-saas-apps-on-postgres-and-citus/
In order to use this library you can either use Mixins or have your models inherit from our custom model class.
Changes in Models:
In whichever files you want to use the library import it:
from django_multitenant.fields import *
from django_multitenant.models import *
All models should inherit the TenantModel class.
Ex: class Product(TenantModel):
Define a static variable named tenant_id and specify the tenant column using this variable.You can define tenant_id in three ways. Any of them is acceptable
Using TenantMeta.tenant_field_name variable
Using TenantMeta.tenant_id variable
Using tenant_id field
Warning
Using tenant_id field directly in the class is not suggested since it may cause collision if class has a field named with 'tenant'
All foreign keys to TenantModel subclasses should use TenantForeignKey in place of
models.ForeignKey
A sample model implementing the above 2 steps:
class Store(TenantModel):
name = models.CharField(max_length=50)
address = models.CharField(max_length=255)
email = models.CharField(max_length=50)
class TenantMeta:
tenant_field_name = "id"
class Product(TenantModel):
store = models.ForeignKey(Store)
name = models.CharField(max_length=255)
description = models.TextField()
class Meta:
unique_together = ["id", "store"]
class TenantMeta:
tenant_field_name = "store_id"
class Purchase(TenantModel):
store = models.ForeignKey(Store)
product_purchased = TenantForeignKey(Product)
class TenantMeta:
tenant_field_name = "store_id"
Changes in Models using mixins:
In whichever files you want to use the library import it by just saying
from django_multitenant.mixins import *
All models should use the TenantModelMixin and the django models.Model or your customer Model class
Ex: class Product(TenantModelMixin, models.Model):
Define a static variable named tenant_id and specify the tenant column using this variable.
Ex: tenant_id='store_id'
All foreign keys to TenantModel subclasses should use TenantForeignKey in place of
models.ForeignKey
Referenced table in TenantForeignKey should include a unique key including tenant_id and primary key
Ex:
class Meta:
unique_together = ["id", "store"]
A sample model implementing the above 3 steps:
class ProductManager(TenantManagerMixin, models.Manager):
pass
class Product(TenantModelMixin, models.Model):
store = models.ForeignKey(Store)
tenant_id='store_id'
name = models.CharField(max_length=255)
description = models.TextField()
objects = ProductManager()
class Meta:
unique_together = ["id", "store"]
class PurchaseManager(TenantManagerMixin, models.Manager):
pass
class Purchase(TenantModelMixin, models.Model):
store = models.ForeignKey(Store)
tenant_id='store_id'
product_purchased = TenantForeignKey(Product)
objects = PurchaseManager()
Automating composite foreign keys at db layer:
Creating foreign keys between tenant related models using TenantForeignKey would automate adding tenant_id to reference queries (ex. product.purchases) and join queries (ex. product__name). If you want to ensure to create composite foreign keys (with tenant_id) at the db layer, you should change the database ENGINE in the settings.py to django_multitenant.backends.postgresql.
Write authentication logic using a middleware which also sets/unsets a tenant for each session/request. This way developers need not worry about setting a tenant on a per view basis. Just set it while authentication and the library would ensure the rest (adding tenant_id filters to the queries). A sample implementation of the above is as follows:
from django_multitenant.utils import set_current_tenant
class MultitenantMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user and not request.user.is_anonymous:
set_current_tenant(request.user.employee.company)
return self.get_response(request)
In your settings, you will need to update the MIDDLEWARE setting to include the one you created.
Set the tenant using set_current_tenant(t) api in all the views which you want to be scoped based on tenant. This would scope all the django API calls automatically(without specifying explicit filters) to a single tenant. If the current_tenant is not set, then the default/native API without tenant scoping is used.
def application_function:
# current_tenant can be stored as a SESSION variable when a user logs in.
# This should be done by the app
t = current_tenant
#set the tenant
set_current_tenant(t);
#Django ORM API calls;
#Command 1;
#Command 2;
#Command 3;
#Command 4;
#Command 5;
Supported APIs:
Most of the APIs under Model.objects.*.
Model.save() injects tenant_id for tenant inherited models.
s=Store.objects.all()[0]
set_current_tenant(s)
#All the below API calls would add suitable tenant filters.
#Simple get_queryset()
Product.objects.get_queryset()
#Simple join
Purchase.objects.filter(id=1).filter(store__name='The Awesome Store').filter(product__description='All products are awesome')
#Update
Purchase.objects.filter(id=1).update(id=1)
#Save
p=Product(8,1,'Awesome Shoe','These shoes are awesome')
p.save()
#Simple aggregates
Product.objects.count()
Product.objects.filter(store__name='The Awesome Store').count()
#Subqueries
Product.objects.filter(name='Awesome Shoe');
Purchase.objects.filter(product__in=p);
Credits
This library uses similar logic of setting/getting tenant object as in django-simple-multitenant. We thank the authors for their efforts.
License
Copyright (C) 2023, Citus Data
Licensed under the MIT license, see LICENSE file for details.
Does citusdata/django-multitenant have a project website?
No homepage URL was recorded for citusdata/django-multitenant in TopGit's last sync. The README tab above frequently contains screenshots and demo links, or check the repository description on GitHub.
Is citusdata/django-multitenant open source?
Yes — citusdata/django-multitenant ships under the MIT license, which makes its source code freely readable (and, depending on license terms, forkable and reusable). Source: github.com/citusdata/django-multitenant.
What is citusdata/django-multitenant?
citusdata/django-multitenant (citusdata/django-multitenant) is a Python project on GitHub. From the project's own README: Python/Django support for distributed multi-tenant databases like Postgres+Citus
What license does citusdata/django-multitenant use?
citusdata/django-multitenant is released under the MIT license. Always verify the LICENSE file directly on GitHub for the authoritative terms — license strings can be edited out of sync with a project's actual stance.
Where do I read more about citusdata/django-multitenant?
This TopGit page is a snapshot — the READ ME tab shows the project's own README content (links stripped, images preserved). The GitHub repository at github.com/citusdata/django-multitenant is the definitive source.
Read full README in the tab above.
Is django-multitenant worth your time?
ChatGPT, Claude and Perplexity can all read this page. Ask one of them what it makes of django-multitenant.