Multi-tenancy¶
Midsummer is multi-tenant: a single deployment serves many independent
convention organizations, fully isolated from one another. The isolation is
schema-based, provided by django-tenants.
The model¶
One PostgreSQL database.
A
publicschema holds shared data:Tenant,Domain,CustomDomain,User,Membership, and Django’s own core apps (auth,admin,contenttypes,oauth2_provider, …).One schema per tenant holds the tenant’s event data: every tenant app (
event,register,staff,vendors,schedule,shop,front,kioskos,utility) is provisioned into each tenant’s schema.
public schema tenant:furrydelphia schema tenant:uproar schema
Tenant, Domain, Event, Registration, Event, Registration,
CustomDomain, User, Vendor, Staff, … Vendor, Staff, …
Membership, auth core
A User is shared (one identity across all tenants). Their per-tenant role
lives in Membership (isTenantSuperuser, developer flags).
How a request lands in the right schema¶
TenantMainMiddleware (top of the middleware stack) reads the request host,
looks up the matching Domain → Tenant, and switches the DB connection to
that tenant’s schema for the duration of the request. It also sets the URLconf:
the tenant URLconf for tenant domains, the public URLconf for the public domain.
See Request resolution for the full walk.
Implications for development¶
Migrations are schema-aware¶
Shared-table migrations run with
migrate_schemas --shared.Tenant-table migrations are applied to every tenant’s schema.
django-tenantsprovidesmigrate_schemasandtenant_command/all_tenants_commandto run a management command across all tenant schemas.
python manage.py migrate_schemas --shared # shared/public schema
python manage.py migrate_schemas # all tenant schemas
python manage.py all_tenants_command event__generate_properties
Commands run inside a tenant context¶
When you run a management command that touches tenant data, it executes against
one tenant’s schema (typically the configured/default tenant locally). Some
commands derive behavior from connection.schema_name, so they must be run from
inside the owning tenant’s context. Example: register__export_reg_timeline
writes per-event data to <dir>/<schema_name>/<event_slug>/ and errors if the
schema is public.
One event per tenant (today)¶
In practice each tenant runs one active event. Events are “swapped in and
out” — true concurrent multi-event access is a documented future goal. Locally
you usually have a single defaultdev tenant with one event.
Where to look¶
Settings:
midsummer/settings.py(SHARED_APPS,TENANT_APPS,PUBLIC_SCHEMA_URLCONF,TENANT_URLCONF).Middleware:
midsummer/middleware.py(TenantMainMiddleware).Tenant model:
tenant/models.py.