Skip to main content

HTTP + WebSocket middleware for multi-tenant Django projects

Project description

django-multitenant-middleware

django-multitenant-middleware is a Django package that provides multi-tenant support for both HTTP and WebSocket (Channels) requests. It resolves tenants dynamically based on subdomains, hostnames, or custom headers.


Installation

pip install django-multitenant-middleware

Settings Configuration (HTTP)

  1. Define your tenant model in settings.py:
CHANNELS_MULTITENANT_TENANT_MODEL = "tenants.Client"

# Optional: Custom resolver class and args
CHANNELS_MULTITENANT_RESOLVER_CLASS = None  # defaults to FlexibleSubdomainTenantResolver
CHANNELS_MULTITENANT_RESOLVER_ARGS = {"base_domain": BASE_DOMAIN}
  1. Add the middleware to your Django MIDDLEWARE list:
MIDDLEWARE = [
    # Other middleware...
    "django_multitenant_middleware.http_middleware.TenantHTTPMiddleware",
]

The middleware automatically sets request.tenant and request.tenant_context.


WebSocket Integration (ASGI)

  1. In asgi.py:
import os
import django
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

from django_multitenant_middleware.ws_middleware import TenantWebSocketMiddleware
from django_multitenant_middleware.resolvers import FlexibleSubdomainTenantResolver
from tenants.models import Client
from core.websocket.routing import websocket_urlpatterns
  1. Setup ASGI:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
django.setup()
django_asgi_app = get_asgi_application()
  1. Configure tenant resolver:
resolver = FlexibleSubdomainTenantResolver(
    base_domain="app.example.com",  # your base domain
    separators=("-", ".")
)
  1. Wrap WebSocket routes:
application = ProtocolTypeRouter({
    "http": django_asgi_app,
    "websocket": TenantWebSocketMiddleware(
        AuthMiddlewareStack(
            URLRouter(websocket_urlpatterns)
        ),
        tenant_model=Client,  # your tenant model
        resolver=resolver,
    ),
})

Tenant Resolvers

  • FlexibleSubdomainTenantResolver: Extracts tenant from subdomain prefixes Example: tenant1-app.example.com → tenant1

  • HeaderTenantResolver: Extracts tenant from a custom HTTP header Example: X-Tenant-ID: tenant1 → tenant1

  • Custom Resolver: Subclass BaseTenantResolver to implement your logic

from channels_multitenant.resolvers import BaseTenantResolver

class MyCustomResolver(BaseTenantResolver):
    def resolve(self, scope) -> str | None:
        # Implement your custom logic
        return "my_tenant"

TenantFetcher (Optional Helper)

TenantFetcher provides async caching for WebSocket tenants:

from channels_multitenant.tenant_fetcher import TenantFetcher
from tenants.models import Client

fetcher = TenantFetcher(Client)
tenant = await fetcher.get_tenant("tenant1")
  • Caches tenants (default 5 minutes)
  • Async-ready for Channels

Notes

  • Ensure CHANNELS_MULTITENANT_TENANT_MODEL points to your tenant model.
  • Missing or invalid settings will raise ImproperlyConfigured.
  • Compatible with Django 4.x+ and Channels 3.x+.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_multitenant_middleware-0.1.2.tar.gz (7.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file django_multitenant_middleware-0.1.2.tar.gz.

File metadata

File hashes

Hashes for django_multitenant_middleware-0.1.2.tar.gz
Algorithm Hash digest
SHA256 ab771ebd6135e8e13667dccd5f3029f0fe7e6ef2ee041a090ad183d1b4a4d3dc
MD5 fff2d40bfeadb0c28bd81ebda7be4442
BLAKE2b-256 606995610b56d11ae6c1554282f59339edcf6497557acb6b7c77ef468ea0fb50

See more details on using hashes here.

File details

Details for the file django_multitenant_middleware-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for django_multitenant_middleware-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a115ba036fbc5acb5b3066e2c052549af66274832586d16a107435520a4c1a54
MD5 729169243d743b915cb71336a0529df9
BLAKE2b-256 12ea0c41f12cc90f337bc1b9deda6e98b041c5ace66f813c15739dd1156499c1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page