A comprehensive Django multi-tenancy solution with schema isolation, tenant-aware middleware, and flexible routing
Project description
django-tenantkit
A Django-native multitenancy framework focused on explicit isolation strategies, clear shared-versus-tenant boundaries, and integration with Django middleware, routing, admin, and provisioning workflows.
Why this package?
Multi-tenant Django systems often need different trade-offs depending on scale, operational model, and isolation requirements. Some solutions focus primarily on PostgreSQL schema isolation, while others assume a narrower routing or provisioning model.
This project aims to provide a more flexible foundation for Django applications that need:
- explicit tenant isolation strategies
- clear separation between shared/public and tenant-scoped data
- Django-native integration points instead of a parallel platform model
- a path toward a reusable package plus a reference example project
Supported isolation strategies
The framework currently supports two primary isolation modes:
| Strategy | Description | Best fit |
|---|---|---|
schema |
Multiple PostgreSQL schemas inside one shared database | Shared infrastructure with strong logical isolation |
database |
A dedicated database per tenant | Stronger operational isolation and backend flexibility |
The shared/public control plane remains separate from tenant-scoped runtime behavior.
See Concepts for the model vocabulary and architectural terms.
Audit and soft-delete
All framework models include mandatory audit tracking via django-auditkit:
created_at,updated_at,deleted_at— timestampscreated_by,updated_by,deleted_by— user tracking (foreign keys toAUTH_USER_MODEL)
This provides:
- Soft delete — records are marked deleted but retained for audit/history
- User attribution — every change is traceable to a user
- Recovery — soft-deleted records can be restored
The framework models (Tenant, TenantInvitation, TenantSetting) all inherit from AuditModel and include these fields automatically. The admin interface shows audit information in a collapsed section at the bottom of each form.
Installation
This repository uses a package-first layout.
The reusable package lives under src/tenantkit, while example/ contains the reference Django project.
For the current setup and integration path, see:
Minimal quickstart
At a high level, a Django project using the framework will:
- add the multitenancy app to
INSTALLED_APPS - add tenant-aware middleware
- add the tenant database router
- define shared and tenant-scoped models
- create one or more tenants
- run the appropriate migration workflow
The current reference Django project lives in example/, while the package source lives in src/tenantkit.
For the guided flow, see Quickstart.
Quick Configuration
Critical: The order of INSTALLED_APPS and MIDDLEWARE matters. See Setup Standard Guide for full details.
# settings.py - Minimal working configuration
INSTALLED_APPS = [
# Django core FIRST (auth before tenantkit)
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# TenantKit AFTER auth
"tenantkit",
# Your apps
"myapp",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware", # BEFORE
"tenantkit.middleware.TenantMiddleware", # AFTER
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
]
DATABASE_ROUTERS = ["tenantkit.routers.TenantRouter"]
TENANTKIT_BOTH_APPS = [
"django.contrib.auth",
"django.contrib.contenttypes",
]
Why this order matters:
django.contrib.authmust come beforetenantkitso User/Group/Permission models register first in thepublicschemaAuthenticationMiddlewaremust come beforeTenantMiddlewareso authentication happens inpublicbefore switching to the tenant schema
Official test command
The current stable validation path is:
uv sync --dev
uv run python example/manage.py test tenantkit
For local development, the repository is managed from the root and the example project acts as a consumer of the package.
See Testing for the current testing entrypoints.
Example project
The repository includes a Django reference project in example/.
It currently serves as:
- the integration environment
- the test harness
- the reference wiring for settings, middleware, routing, and admin behavior
The reusable package itself lives in src/tenantkit.
See Example Project.
Documentation
Public documentation:
- Installation
- Setup Standard Guide - Start here for configuration order
- Configuration Guide
- Quickstart
- Concepts
- Commands
- Provisioning
- Testing
- Example Project
- API Reference
Technical and architectural material:
Compatibility
| Project status | Python | Django |
|---|---|---|
| Current main branch | 3.12, 3.13 | 6.0 |
- Schema isolation requires PostgreSQL
- Database isolation depends on backend-specific provisioning and runtime support
Status
This project is under active development.
Current transition goals include:
- refining the public documentation structure
- stabilizing the new package-first repository layout
- keeping the
example/project as the reference integration environment
Contributing
See CONTRIBUTING.md. All changes should go through Pull Requests.
License
MIT License. See LICENSE.
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
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_tenantkit_core-0.2.3.tar.gz.
File metadata
- Download URL: django_tenantkit_core-0.2.3.tar.gz
- Upload date:
- Size: 71.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1df648f25d599a8616d833c094a163ab781ea6bb1ac45e85c65f2224cdbc62d6
|
|
| MD5 |
74874615aa52f670de37df0bcd4cc864
|
|
| BLAKE2b-256 |
75f5430d3ee268a6b25d23d5583c24977b872048314156010afc6c4ea5415cb1
|
Provenance
The following attestation bundles were made for django_tenantkit_core-0.2.3.tar.gz:
Publisher:
publish.yml on pdigonzelli/django-tenantkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_tenantkit_core-0.2.3.tar.gz -
Subject digest:
1df648f25d599a8616d833c094a163ab781ea6bb1ac45e85c65f2224cdbc62d6 - Sigstore transparency entry: 1496533003
- Sigstore integration time:
-
Permalink:
pdigonzelli/django-tenantkit@39ea93ddacfd0907f200d96f5bede369eb4eac71 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/pdigonzelli
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@39ea93ddacfd0907f200d96f5bede369eb4eac71 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_tenantkit_core-0.2.3-py3-none-any.whl.
File metadata
- Download URL: django_tenantkit_core-0.2.3-py3-none-any.whl
- Upload date:
- Size: 91.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b611976a58d39263ee4592ca2570ca5e7a0e936eec98a0246737f18b928ccf56
|
|
| MD5 |
bad8ece8f08cb554d448b7309f7b33f7
|
|
| BLAKE2b-256 |
0846e043d12b544f67fce2e1e43e26288ac737296978ff90b05c5d5f7ebf2029
|
Provenance
The following attestation bundles were made for django_tenantkit_core-0.2.3-py3-none-any.whl:
Publisher:
publish.yml on pdigonzelli/django-tenantkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_tenantkit_core-0.2.3-py3-none-any.whl -
Subject digest:
b611976a58d39263ee4592ca2570ca5e7a0e936eec98a0246737f18b928ccf56 - Sigstore transparency entry: 1496533077
- Sigstore integration time:
-
Permalink:
pdigonzelli/django-tenantkit@39ea93ddacfd0907f200d96f5bede369eb4eac71 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/pdigonzelli
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@39ea93ddacfd0907f200d96f5bede369eb4eac71 -
Trigger Event:
push
-
Statement type: