What this prompt does
This prompt designs multi-tenancy for a [project_type] Django app serving [tenant_count] tenants, each with [users_per_tenant] users and [data_volume] of data. It asks the AI to choose and justify a tenancy strategy ([tenancy_strategy]) against your [isolation_level] requirement, scalability needs, and operational complexity, then implement a Tenant model (name, slug, domain, plan, settings JSONField) and a TenantMiddleware that resolves the tenant from [tenant_resolution] and stores it in thread-local or a ContextVar.
The core safety mechanism is a TenantMixin applied to [tenant_scoped_models]: it adds a tenant ForeignKey, overrides the default manager to auto-filter by the current tenant, and overrides save() to set the tenant from context. It layers on isolation verification — middleware blocking cross-tenant access, serializer validation rejecting foreign tenant IDs in relationships, and a [test_isolation_method] helper — a shared non-tenanted manager pattern for [shared_models] like plans and feature flags, and a super-admin view that can switch tenants and view cross-tenant analytics for [admin_analytics].
When to use it
- You're building B2B SaaS where tenant data must never leak across customers
- You want an auto-filtering manager so developers can't forget the tenant filter
- You need tenant resolution from a subdomain or a header for API clients
- You want isolation tests that prove two tenants can't see each other's data
- You have global data (plans, feature flags) that should bypass tenant scoping
- You need a super-admin able to switch tenants and view cross-tenant metrics
- You want the tenancy choice justified against your isolation and scaling needs, not assumed
Example output
The AI returns a justified strategy choice with trade-offs, a Tenant model definition, a TenantMiddleware using a ContextVar, the TenantMixin with manager and save() overrides, isolation-verification code, a separate manager for [shared_models], and an admin tenant-switcher view for [admin_analytics]. Expect a written trade-off discussion plus code blocks per numbered section, so the reasoning behind row-level isolation is explicit and reviewable.
Pro tips
- State
[isolation_level]as strict explicitly so the AI defends row-level filtering with proper enforcement rather than convention - Prefer a ContextVar over thread-local if any async code paths exist, since thread-local doesn't carry across async contexts cleanly
- Always pair the auto-filtering manager with isolation tests from
[test_isolation_method]— one missing filter is the bug you find in production - Keep
[shared_models]on a separate non-tenanted manager so global config isn't accidentally scoped to a tenant - Make serializer validation reject foreign tenant IDs in
[tenant_scoped_models]relationships, not just top-level objects - Reject requests with an unknown tenant from
[tenant_resolution]early with a 404 rather than letting them fall through - If
[tenant_resolution]supports both subdomain and header, define a clear precedence so requests resolve deterministically