Django Tenants Knowledge Base

Multi-Tenant Architecture with Django + PostgreSQL


Table of Contents

  1. Introduction
  2. What is Multi-Tenancy?
  3. Multi-Tenant Architecture Approaches
  4. Why Use django-tenants
  5. Core Concepts
  6. How django-tenants Works
  7. PostgreSQL Schema Fundamentals
  8. Request Flow Architecture
  9. Project Setup Guide
  10. Configuration Deep Dive
  11. Shared Apps vs Tenant Apps
  12. Tenant and Domain Models
  13. Database Schema Lifecycle
  14. Middleware and Request Routing
  15. Migrations in Multi-Tenant Systems
  16. CRUD Operations in Tenant Context
  17. Admin Panel Integration
  18. Authentication Considerations
  19. Best Practices
  20. Production Recommendations
  21. Security Considerations
  22. Celery and Background Tasks
  23. Common Pitfalls
  24. Architecture Diagrams
  25. Example SaaS Structure
  26. Recommended Folder Structure
  27. Deployment Notes
  28. Debugging Tips
  29. Final Mental Model

1. Introduction

django-tenants enables building SaaS-style applications where:

This approach is called:

Shared Database + Separate Schemas


2. What is Multi-Tenancy?

A tenant represents:

inside a SaaS application.

Example:

Tenant Subdomain
Ferrari ferrari.myapp.com
McLaren mclaren.myapp.com

Each tenant should only access its own data.


3. Multi-Tenant Architecture Approaches

A. Separate App + Separate DB

Tenant A -> Django App A -> DB A
Tenant B -> Django App B -> DB B

Pros

Cons


B. Shared App + Separate Schemas (django-tenants)

One Django App
        |
One PostgreSQL Database
        |
+-------------------+
| public schema     |
| ferrari schema    |
| mclaren schema    |
+-------------------+

Pros

Cons


C. Shared App + Shared Tables

All tenants use same tables
tenant_id column separates data

Pros

Cons


4. Why Use django-tenants

Benefits:

Official Docs:

https://django-tenants.readthedocs.io/


5. Core Concepts


Tenant

Represents a customer/client.

Example:

class Client(TenantMixin):
    name = models.CharField(max_length=100)

Domain

Maps subdomain -> tenant.

Example:

ferrari.localhost -> Ferrari Tenant

Schema

PostgreSQL namespace containing tables.

Example:

public
ferrari
mclaren

Shared Apps

Apps stored in public schema.

Examples:


Tenant Apps

Apps stored inside tenant schemas.

Examples:


6. How django-tenants Works

High-level flow:

  1. Request arrives
  2. Middleware reads hostname
  3. Finds tenant from domain table
  4. Sets PostgreSQL search_path
  5. ORM queries automatically use correct schema

7. PostgreSQL Schema Fundamentals

Schemas behave like folders.

Example:

Database
├── public
├── ferrari
└── mclaren

Each schema contains its own tables.


Example

Ferrari Schema

ferrari.projects
ferrari.tasks

McLaren Schema

mclaren.projects
mclaren.tasks

Same table names.

Different data.


8. Request Flow Architecture

Complete Flow

[Diagram]

9. Project Setup Guide


Install Packages

pip install django-tenants psycopg2-binary

or

uv add django-tenants

PostgreSQL Requirement

django-tenants requires PostgreSQL.


Update Database Engine

DATABASES = {
    "default": {
        "ENGINE": "django_tenants.postgresql_backend",
    }
}

Add Router

DATABASE_ROUTERS = (
    'django_tenants.routers.TenantSyncRouter',
)

Add Middleware

MUST be first.

MIDDLEWARE = [
    'django_tenants.middleware.main.TenantMainMiddleware',
]

10. Configuration Deep Dive


Shared Apps

SHARED_APPS = (
    'django_tenants',
    'customers',
    'django.contrib.contenttypes',
    'django.contrib.auth',
)

These tables live in:

public schema

Tenant Apps

TENANT_APPS = (
    'projects',
    'tasks',
)

These tables live in:

tenant schemas

Installed Apps

INSTALLED_APPS = list(SHARED_APPS) + [
    app for app in TENANT_APPS
    if app not in SHARED_APPS
]

11. Shared Apps vs Tenant Apps

Shared Apps

[Diagram]

Tenant Apps

[Diagram]

12. Tenant and Domain Models


Tenant Model

from django_tenants.models import TenantMixin

class Client(TenantMixin):
    name = models.CharField(max_length=100)

    auto_create_schema = True

Domain Model

from django_tenants.models import DomainMixin

class Domain(DomainMixin):
    pass

Settings

TENANT_MODEL = "customers.Client"
TENANT_DOMAIN_MODEL = "customers.Domain"

13. Database Schema Lifecycle


Tenant Creation

[Diagram]

Auto Schema Creation

auto_create_schema = True

When tenant saved:


14. Middleware and Request Routing

Core middleware:

TenantMainMiddleware

Responsibilities:


Tenant Access

request.tenant

Example:

def dashboard(request):
    print(request.tenant)

15. Migrations in Multi-Tenant Systems

Never use:

python manage.py migrate

Use:

python manage.py migrate_schemas

Shared Only

python manage.py migrate_schemas --shared

Migration Flow

[Diagram]

16. CRUD Operations in Tenant Context

No special ORM logic needed.


Query Example

Project.objects.all()

Automatically queries:

current tenant schema

Create Example

Project.objects.create(
    name="Win Championship"
)

Automatically saves into current tenant schema.


17. Admin Panel Integration

Use:

from django_tenants.admin import TenantAdminMixin

Example:

@admin.register(Client)
class ClientAdmin(TenantAdminMixin, admin.ModelAdmin):
    pass

18. Authentication Considerations

Very important.

Without authentication:

You MUST implement:


Recommended Pattern

User belongs to Tenant

Example

class Membership(models.Model):
    user = models.ForeignKey(User)
    tenant = models.ForeignKey(Client)

19. Best Practices


Always Use PostgreSQL

Required for schemas.


Keep Shared Apps Minimal

Only global/shared data.

Examples:


Put Business Logic in Tenant Apps

Examples:


Use Subdomains

Best routing strategy.

Examples:

tenant1.myapp.com
tenant2.myapp.com

Add Tenant-Aware Permissions

Critical for security.


Separate Background Tasks

Celery tasks need schema context.


Monitor Schema Count

Thousands of schemas can impact performance.


Use Custom User Model Early

Always start with:

AbstractUser

20. Production Recommendations


Use Wildcard DNS

Example:

*.myapp.com

Reverse Proxy

Use:


SSL

Use wildcard certificates.

Example:

*.myapp.com

Backups

Backup strategy should include:


21. Security Considerations


Never Trust Subdomain Alone

Validate:


Add Middleware Validation

Ensure:

user belongs to request.tenant

Prevent Cross-Tenant Data Leaks

Never manually override schema without caution.


22. Celery and Background Tasks

Celery tasks do not have request object.

Therefore:

request.tenant

is unavailable.


Solution

Pass schema explicitly.

Example:

from django_tenants.utils import tenant_context

with tenant_context(tenant):
    # tenant-aware logic

23. Common Pitfalls


Forgetting migrate_schemas

This is the #1 mistake.


Using SQLite

Not supported.


Putting Tenant Models in Shared Apps

Incorrect separation can break architecture.


Forgetting Public Tenant

You must create:

public schema tenant

Wrong Middleware Order

Tenant middleware must be FIRST.


24. Architecture Diagrams


Full System Architecture

[Diagram]

Database Layout

[Diagram]

25. Example SaaS Structure

Example:

SaaS CRM

Shared

users
subscriptions
billing
tenant management

Tenant Specific

customers
leads
projects
notes
tasks

26. Recommended Folder Structure

project/
├── customers/
│   ├── models.py
│   ├── admin.py
│
├── projects/
├── tasks/
├── config/
│   ├── settings.py
│   ├── urls.py

27. Deployment Notes


Local Development

Use:

tenant.localhost

Docker

Use PostgreSQL container.


Kubernetes

Recommended for large SaaS platforms.


28. Debugging Tips


Check Current Schema

SHOW search_path;

Set Schema Manually

SET search_path TO ferrari;

Include Public Schema

SET search_path TO ferrari, public;

29. Final Mental Model

The MOST important concept:

django-tenants changes PostgreSQL search_path
based on incoming request domain

Everything else builds on this.


Ultimate Simplified Flow

[Diagram]

Key Takeaways


Recommended Learning Path

  1. Understand PostgreSQL schemas
  2. Learn shared vs tenant apps
  3. Understand middleware schema switching
  4. Build CRUD example
  5. Add authentication
  6. Add tenant permissions
  7. Add Celery support
  8. Deploy with wildcard domains

References

Official Documentation:

https://django-tenants.readthedocs.io/

Main Concepts Covered From Transcript: