Skip to content

Middleware

TenantMiddleware resolves the tenant of each request, registers its database and activates it for the request's lifetime. It supports both WSGI and ASGI stacks.

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django_db_tenants.middleware.TenantMiddleware",  # before sessions and auth
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
]

Behaviour

Request request.tenant Database for tenant apps Response
Path starts with an EXEMPT_PATHS prefix None shared the view's
Resolver returns None (control host) None shared the view's
Resolver returns a client the client the client's the view's
Resolver raises TenantError not set NOT_FOUND_HANDLER(request, exc), or 404 Unknown tenant.

The full sequence is described in Architecture.

Custom not-found response

# myproject/tenancy.py
from django.shortcuts import render


def tenant_not_found(request, exc):
    return render(request, "unknown_tenant.html", {"host": request.get_host()}, status=404)


# settings.py
DB_TENANTS = {"NOT_FOUND_HANDLER": "myproject.tenancy.tenant_not_found"}

exc is a TenantNotFound or a TenantInactive; see Exceptions.

django_db_tenants.middleware

Resolve the tenant for each request and activate it for the request's lifetime.

Place BEFORE django.contrib.sessions and django.contrib.auth middleware so that session and user lookups are already routed to the tenant database.

TenantMiddleware

sync_capable class-attribute instance-attribute

sync_capable = True

async_capable class-attribute instance-attribute

async_capable = True

get_response instance-attribute

get_response = get_response