Install & Compatibility
Where this runs
tested against v3.14.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.000s · 67.6MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 3.5s · import 0.000s · 68MB
67MB installed
● package 67MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
TenantMixin
✓ from django_tenants.models import TenantMixin
✗ from django_tenants.models import TenantMixin
This quickstart demonstrates the core steps for setting up `django-tenants`. It involves configuring your Django `settings.py` with `SHARED_APPS`, `TENANT_APPS`, `DATABASE_ROUTERS`, and `TenantMainMiddleware`. You then define your `TenantMixin` and `DomainMixin` models, run initial migrations for shared applications using `migrate_schemas --shared`, and finally create tenant instances, which automatically create and migrate their respective schemas. [5, 8, 12, 16]
import os
import django
from django.conf import settings
from django.core.management import call_command
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings')
django.setup()
# Assuming you have an app 'customers' with Client (TenantMixin) and Domain (DomainMixin) models
# from customers.models import Client, Domain # Uncomment in your actual project
# --- Example of creating a public tenant (adapt to your models) ---
# In your settings.py:
# TENANT_MODEL = "customers.Client"
# TENANT_DOMAIN_MODEL = "customers.Domain"
# Create a dummy Client and Domain for demonstration if not already existing
# (In a real scenario, this would involve your actual Client and Domain models)
class MockClient(object):
id = 1 # Dummy ID
schema_name = 'public'
name = 'Public Tenant'
class MockDomain(object):
domain = 'localhost'
tenant = MockClient()
is_primary = True
print("1. Ensure settings are configured (SHARED_APPS, TENANT_APPS, MIDDLEWARE, DATABASE_ROUTERS).")
print("2. Run initial migrations for shared schema:")
try:
# In a real project, this would be `call_command('migrate_schemas', '--shared')`
# For this quickstart, we'll simulate output, as actual migration requires a full Django setup
print(" Simulating: python manage.py migrate_schemas --shared")
# call_command('migrate_schemas', '--shared', verbosity=0)
print(" Shared schema migrations complete.")
except Exception as e:
print(f" Error during shared migrations (expected if not a full Django setup): {e}")
print("3. Create a tenant (e.g., in a Django shell or a management command):")
try:
# Example of creating a tenant (replace with your actual Client/Domain models and logic)
# tenant = Client(schema_name='tenant1', name='Tenant One', paid_until='2030-12-31', on_trial=False)
# tenant.save() # This automatically creates and syncs the schema
# domain = Domain()
# domain.domain = 'tenant1.localhost'
# domain.tenant = tenant
# domain.is_primary = True
# domain.save()
print(" Simulating tenant creation:")
print(" client = Client(schema_name='tenant1', name='Tenant One', ...)")
print(" client.save() # Schema 'tenant1' created and migrated automatically")
print(" domain = Domain(domain='tenant1.localhost', tenant=client, is_primary=True)")
print(" domain.save()")
print(" Tenant 'tenant1' created with domain 'tenant1.localhost'.")
except Exception as e:
print(f" Error during tenant creation (expected if not a full Django setup): {e}")
print("4. Access tenant-specific data via hostname (e.g., tenant1.localhost:8000).")
print(" The TenantMainMiddleware will automatically switch the database schema.")
Debug
Known issues
breaking`django-tenants` v3.x has aligned with newer Django and Python versions. Specifically, v3.10.0 and v3.8.0 added support for Django 5.x and Python 3.13, while dropping support for older Django versions (e.g., 3.x, 4.0) and Python versions (e.g., 3.8, 3.1) in previous v3.x releases. Always check release notes for specific version compatibility when upgrading. [15]fixReview `django-tenants` release notes (e.g., GitHub releases) before upgrading to ensure compatibility with your Django and Python environment. Upgrade your Django and Python versions if necessary.
affects: 3.x onwards
breakingAs of v3.0.0, `django-tenants` removed `psycopg2` as a direct dependency. While this provides flexibility, it means users must explicitly install a PostgreSQL adapter like `psycopg2-binary` or `psycopg3` for database connectivity. [13]fixExplicitly install your preferred PostgreSQL adapter: `pip install psycopg2-binary` or `pip install "psycopg[binary]"` (for psycopg3).
affects: >=3.0.0
gotchaThe `auto_drop_schema` field on your `TenantMixin` model defaults to `False`. If you explicitly set it to `True`, deleting a tenant model instance through the ORM will *automatically drop its associated PostgreSQL schema* without further confirmation. This can lead to irreversible data loss. [3]fixExercise extreme caution when setting `auto_drop_schema = True` on your tenant model. Understand the implications and ensure proper backup strategies or manual schema management if this flag is enabled.
affects: All versions
gotchaRunning the standard `python manage.py migrate` command will apply migrations to *both* shared and tenant schemas, which is often not the desired behavior. You must use `python manage.py migrate_schemas --shared` for shared apps and `python manage.py tenant_command migrate --schema=yourtenant` (or `all_tenants_command`) for tenant-specific apps. [5]fixAlways use `migrate_schemas --shared` for shared applications and `tenant_command migrate` or `all_tenants_command` for tenant-specific applications. Do not use `manage.py migrate` directly after initial setup.
affects: All versions
gotchaFor `request.tenant` to be available in your templates, `django.template.context_processors.request` must be included in the `context_processors` option within your `TEMPLATES` setting in `settings.py`. [5]fixEnsure your `TEMPLATES` setting includes `'django.template.context_processors.request'` in the `'OPTIONS': {'context_processors': [...]}` list. affects: All versions
gotchaWhen working with ASGI applications (e.g., Dpahne, Uvicorn) and custom tenant resolution logic outside of `TenantMainMiddleware`, relying on `thread_locals` or similar global state for tenant context can be problematic due to the asynchronous nature of ASGI servers. This can lead to incorrect tenant context being applied. [17]fixFor ASGI applications, ensure tenant context is explicitly passed or managed within the async request/task scope. Prefer `schema_context` or `tenant_context` utilities for explicit context switching in non-request-bound operations.
affects: All versions (especially with ASGI)
Upgrade
Version history
3.14.0latest on PyPI · released Aug 5, 2026
Audit
Dependencies
DjangorequiredCore web framework dependency.
PostgreSQLrequiredDatabase backend required for schema-based multi-tenancy. [1]
psycopg2-binaryoptionalPostgreSQL adapter for Python. `django-tenants` no longer lists it as a direct requirement but it's necessary for database connectivity. `psycopg3` is also supported. [13, 15]
psycopg3optionalModern PostgreSQL adapter for Python. `django-tenants` no longer lists it as a direct requirement but it's necessary for database connectivity. `psycopg2-binary` is also supported. [13, 15]