你也想成為房屋改造大師嗎?或許在現實有點困難,但我們將 Django 變身為多租戶架構卻很容易,今天讓我們來一探究竟吧!
首先來看看我們目前的目錄結構,現在我們的 web 目錄為 ./example_tenant
.
├── data # 資料存放目錄
│ └── postgres
│ └── data
├── docker-compose.yml # docker compose 設定檔
├── docker-entrypoint.sh # entry-point 設定檔
├── Dockerfile # Dockerfile
├── web # Django 專案主目錄
│ ├── db.sqlite3 # Django 原生 Database SQLite
│ ├── main # Django 主要應用程式
│ │ ├── asgi.py
│ │ ├── __init__.py
│ │ ├── settings.py # Django 主設定檔
│ │ ├── urls.py
│ │ └── wsgi.py
│ └── manage.py # Django command-line 命令程式
└── requirements.txt # python 套件清單
settings.py 為 Django 的主設定擋,我們將調整設定與參數來架設我們的多租戶架構
設定資料庫引擎,使用我們已經安裝的 postgresql 與其設定,這裡的 host 會對應到 docker-compose.yml 中的 service name
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django_tenants.postgresql_backend',
'NAME': 'db_name',
'USER': 'db_user',
'PASSWORD': 'db_password',
'HOST': 'db',
'PORT': '5432',
'TIME_ZONE': 'Asia/Taipei',
}
}
設定資料庫路由器
# settings.py
DATABASE_ROUTERS = (
'django_tenants.routers.TenantSyncRouter',
)
新增 middleware
# settings.py
MIDDLEWARE = (
'django_tenants.middleware.main.TenantMainMiddleware',
#...
)
新增 context_processors
# settings.py
TEMPLATES = [
{
#...
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
#...
],
},
},
]
建立應用程式來管理我們的租戶,這裡將新增一個 應用程式(app)與模型(model),細節會放到後續的文章會再詳細講解。
docker exec 指令可以在容器中運行一個新命令
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
--workdir 指定運行的目錄
新增 customers 應用程式
docker exec --workdir /opt/app/web example_tenant_web \
python3.10 manage.py startapp customers
建立租戶模型 models.py ,這裡需要繼承 TenantMixin 與 DomainMixin,其他欄位可以自行新增。
這裡新增兩個模型 Client (租戶)與 domain(網域)
# customers/models.py
from django.db import models
from django_tenants.models import TenantMixin, DomainMixin
class Client(TenantMixin):
name = models.CharField(max_length=100)
paid_until = models.DateField()
on_trial = models.BooleanField()
created_on = models.DateField(auto_now_add=True)
# default true, schema will be automatically created and synced when it is saved
auto_create_schema = True
class Domain(DomainMixin):
pass
建立管理介面,Django 自帶管理介面,只要建立了 model 則可以快速生成管理介面。
# cuustomers/admin.py
from django.contrib import admin
from django_tenants.admin import TenantAdminMixin
from customers.models import Client
@admin.register(Client)
class ClientAdmin(TenantAdminMixin, admin.ModelAdmin):
list_display = ('name', 'paid_until')
INSTALLED_APPS 是 Django 設定應用程式的列表。在建立應用程式之後通常就會使用此列表加入到專案中。
而在多租戶架構下,我們可以自行設定要租戶共享的應用程式 SHARED_APPS 與租戶獨自擁有的應用程式 TENANT_APPS。
# settings.py
# Application definition
SHARED_APPS = (
'django_tenants', # mandatory
'customers', # you must list the app where your tenant model resides in
'django.contrib.contenttypes',
)
TENANT_APPS = (
'django.contrib.auth',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.sitemaps',
)
INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS]
設定站台。因為將 Django 自帶的管理介面設定為租戶獨享,會無法取得預設站台,這裡要先指定預設站台
# settings.py
SITE_ID = 1
設定租戶與模型的位置
# settings.py
TENANT_MODEL = "customers.Client" # app.Model
TENANT_DOMAIN_MODEL = "customers.Domain" # app.Model
多租戶架構的設置到這裡就大致完成了,最後一步則是遷移資料庫。
有了模型後要如何讓資料庫生成資料表呢?遷移指令是 Django 將 model 應用至資料庫結構中的方式。
基本指令如下
migrate # 負責應用遷移
makemigrations # 根據模型建立遷移檔案
sqlmigrate # 列出遷移時使用的 SQL 語法
showmigrations # 列出遷移狀態
而 django-tenant 額外提供只遷移 SHARED_APPS 的語法
migrate_schemas --shared # 應用 SHARED_APPS
而使用 migrate 則將同時作用於 SHARED_APPS 與 TENANT_APPS。
現在讓我們開始進行遷移吧!
建立遷移檔案
docker exec --workdir /opt/app/web example_tenant_web \
python3.10 manage.py makemigrations
...
Migrations for 'customers':
customers/migrations/0001_initial.py
- Create model Client
- Create model Domain
應用遷移
docker exec --workdir /opt/app/web example_tenant_web \
python3.10 manage.py migrate
...
=== Starting migration
Operations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions, sites
Running migrations:
Applying customers.0001_initial...
OK
大功告成!
最後查看一下當前的資料庫結構,由於還沒有建立租戶,所以只有 SHARED_APPS 在 pubic schema 生成的資料表如下:
Schema | Name | Type | Owner
--------+---------------------+-------+---------
public | customers_client | table | db_user
public | customers_domain | table | db_user
public | django_content_type | table | db_user
public | django_migrations | table | db_user
(4 rows)
專案目錄結構:
.
├── data
│ └── postgresql
│ └── data
├── docker-compose.yml
├── docker-entrypoint.sh
├── Dockerfile
├── LICENSE
├── README.md
├── requirements.txt
└── web
├── customers
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── db.sqlite3
├── main
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Django 的多租戶架構變身成功!明天我們將請第一個房客入住,『第一個房客,建立租戶』