Easy to create applications that use tenants in django
Project description
easy-tenants
This is a Django app for managing multiple tenants on the same project instance using a shared approach.
Background
There are typically three solutions for solving the multitenancy problem:
- Isolated Approach: Separate Databases. Each tenant has it’s own database.
- Semi Isolated Approach: Shared Database, Separate Schemas. One database for all tenants, but one schema per tenant.
- Shared Approach: Shared Database, Shared Schema. All tenants share the same database and schema. There is a main tenant-table, where all other tables have a foreign key pointing to.
This application implements the third approach, which in our opinion, is the best solution for a large amount of tenants.
For more information: Building Multi Tenant Applications with Django
Below is a demonstration of the features in each approach for an application with 5000 tenants.
Approach | Number of DB | Number of Schemas | Django migration time | Public access |
---|---|---|---|---|
Isolated | 5000 | 5000 | slow (1/DB) | No |
Semi Isolated | 1 | 5000 | slow (1/Schema) | Yes |
Shared | 1 | 1 | fast (1) | Yes |
Installation
Assuming you have django installed, the first step is to install django-easy-tenants
.
python -m pip install django-easy-tenants
Now you can import the tenancy module in your Django project.
Setup
It is recommended to install this app at the beginning of a project. In an existing project, depending on the structure of the models, the data migration can be hard.
Add easy_tenants
to your INSTALLED_APPS
on settings.py
.
settings.py
INSTALLED_APPS = [
...,
'easy_tenants',
]
Create a model which will be the tenant of the application.
yourapp/models.py
from django.db import models
class Customer(models.Model):
...
Your models, which must have isolated data per tenant, we need to add the foreign field from the Customer model.
and objects need to be replaced with TenantManager()
.
from django.db import models
from easy_tenants.models import TenantManager
class Product(models.Model):
tenant = models.ForeignKey(Customer, on_delete=models.CASCADE, editable=False)
name = models.CharField(max_length=10)
objects = TenantManager()
If you prefer you can use TenantAwareAbstract
to implement the save method for you,
so when saving an object the tenant will be automatically defined.
class Product(TenantAwareAbstract):
tenant = models.ForeignKey(Customer, on_delete=models.CASCADE, editable=False)
name = models.CharField(max_length=10)
objects = TenantManager()
If your foreign field has a name other than tenant
you can change it with a settings. (default is "tenant"
)
# models.py
class Product(TenantAwareAbstract):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, editable=False)
name = models.CharField(max_length=10)
objects = TenantManager()
# settings.py
EASY_TENANTS_TENANT_FIELD = "customer"
To obtain the data for each tenant, it is necessary to define which tenant will be used:
from easy_tenants import tenant_context
with tenant_context(customer):
Product.objects.all() # filter by customer
To define the tenant to be used, this will depend on the business rule used. Here is an example for creating middleware that defines a tenant:
from django.http import HttpResponse
from easy_tenants import tenant_context
class TenantMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
customer = get_customer_by_request(request)
if not customer:
return HttpResponse("Select tenant")
with tenant_context(customer):
return self.get_response(request)
If you want to separate the upload files by tenant, you need to change the DEFAULT_FILE_STORAGE
configuration (only available for local files).
DEFAULT_FILE_STORAGE = 'easy_tenants.storage.TenantFileSystemStorage'
Running the example project
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
Access the page /admin/
, create a Customer
.
Motivation
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for django-easy-tenants-0.7.1.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1dff08dd945a8597e172a1e22f4304f38968fd4a721ed1fad43db2e335cdd0a1 |
|
MD5 | 53b180cac34d9ccc19907e62783f0759 |
|
BLAKE2b-256 | 78a68888611c75e84c20a9b54287874b305580ce494102827f27aed03bc3b9fd |
Hashes for django_easy_tenants-0.7.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9f80ccc1327cdeaa2c9474d73b4fc8373eeaeeb42b56aa750f9742c830a5fc43 |
|
MD5 | 9ead22d13c9466d6583ae16930c3566d |
|
BLAKE2b-256 | a341ed7fd711c8784f1393a68b7b2a385bb9daa8f81795521b0ac3c72b631865 |