# Tenant Creation Example
```sh
python manage.py create_tenant \
--domain-domain=api.client1.x.io \
--schema_name=client1 \
--name="Client 1"
```
## This creates:
- Tenant record: schema_name="client1", name="Client 1"
- Domain record: domain="api.client1.x.io" → tenant_id=$tenant_id
- PostgreSQL schema: Creates client1 schema with all tenant-specific tables
## Request Example
When a request comes to https://api.client1.x.io/api/v1/audits/:
1. Middleware extracts hostname: api.client1.x.io
2. Queries: SELECT * FROM tenancy_domain WHERE domain='api.client1.x.io'
3. Gets tenant with schema_name='client1'
4. Switches PostgreSQL connection to client1 schema
5. All subsequent queries operate within client1 schema
# Using localhost on laptop
## Development Setup Options
1. Localhost with Port (Simplest)
```sh
python manage.py create_tenant \
--domain-domain=localhost:8000 \
--schema_name=dev1 \
--name="Dev Tenant 1"
```
Access via: http://localhost:8000
2. Subdomain Localhost (Recommended)
```sh
python manage.py create_tenant \
--domain-domain=client1.localhost \
--schema_name=client1 \
--name="Client 1 Dev"
python manage.py create_tenant \
--domain-domain=client2.localhost \
--schema_name=client2 \
--name="Client 2 Dev"
```
Add to /etc/hosts (on Mac/Linux) or C:\Windows\System32\drivers\etc\hosts (Windows):
```sh
127.0.0.1 client1.localhost
127.0.0.1 client2.localhost
```
Access via:
- http://client1.localhost:8000
- http://client2.localhost:8000
3. Docker Development
```sh
docker compose -f local.yml run --rm django python manage.py create_tenant \
--domain-domain=xxx.localhost \
--schema_name=xxx \
--name=xxx
```
4. Public Schema Fallback
The system is configured with:
```sh
SHOW_PUBLIC_IF_NO_TENANT_FOUND = True # config/settings/base.py:196
```
This means if no tenant matches the domain, it falls back to the public schema instead of
throwing a 404.
How It Works in Development
The middleware (TenantMainMiddleware) extracts the hostname using:
```python
hostname = remove_www(request.get_host().split(':')[0])
```
So for http://client1.localhost:8000, it extracts client1.localhost and matches it against the
database.
Testing Multiple Tenants
You can easily test multiple tenants locally:
# Create multiple tenants
```sh
python manage.py create_tenant --domain-domain=tenant1.localhost --schema_name=tenant1
--name="Tenant 1"
python manage.py create_tenant --domain-domain=tenant2.localhost --schema_name=tenant2
--name="Tenant 2"
# Access different tenants
curl http://tenant1.localhost:8000/api/v1/audits/
curl http://tenant2.localhost:8000/api/v1/audits/
```
Each will access completely separate data in their own PostgreSQL schemas (tenant1 and
tenant2).
No real DNS required - just local hostname resolution via /etc/hosts or browser requests.