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.1.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.1.tar.gz.

File metadata

File hashes

Hashes for django_multitenant_middleware-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7af9febfa38f8c19ec740a046e2598a4fb4655f95a3f69a454913583ffb19fd2
MD5 131aaa04237c03940d3521524799cbca
BLAKE2b-256 064341a2e7c5d1b714094c0ab7587eac97b308dedaf837eb665c5479cb01d207

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for django_multitenant_middleware-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c8851e599220839e429fad25db9777e3482d526da3a6e082c6cd5add7db82ac2
MD5 61881a84deabc936318b4798f052361c
BLAKE2b-256 3983d3df18b6e46df4962c8b7910c2c364e22ff22c66bd0c7b9fc21d7626d611

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