You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Django实现单代码库适配多客户多数据库的方案咨询

Django多客户独立数据库与配置实现方案

核心思路

复用同一套代码,通过动态加载客户专属配置和数据库隔离机制,让每个客户拥有独立数据库与配置,新增客户仅需添加配置文件和创建数据库,代码变更时统一更新即可,无需为每个客户重复操作。

1. 配置文件拆分与动态加载

  • 把通用配置(如中间件、INSTALLED_APPS、通用业务参数)保留在主settings.py中,每个客户的独立配置(数据库、专属静态路径、自定义业务参数)放在单独的配置目录,比如configs/customer_a.py、configs/customer_b.py
  • 在settings.py中通过环境变量或请求域名动态加载对应客户的配置:
# settings.py
import os
import importlib

# 优先从环境变量取客户标识,也可从请求域名解析
CUSTOMER_ID = os.environ.get('CUSTOMER_ID', 'default')

# 加载客户专属配置并合并到全局
customer_config = importlib.import_module(f'configs.{CUSTOMER_ID}')
globals().update(vars(customer_config))
  • 客户配置文件示例(configs/customer_a.py):
# 独立数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'customer_a_restaurant',
        'USER': 'db_user',
        'PASSWORD': 'customer_a_pass',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

# 客户专属静态文件前缀
STATIC_URL = '/customer_a/static/'

# 其他自定义参数,比如餐厅名称
RESTAURANT_NAME = 'A餐厅'

2. 数据库路由(按需选择)

如果需要单进程处理多个客户请求(比如共享一个WSGI进程),可以用Django的数据库路由实现动态切换:

  • 创建db_router.py文件:
from threading import local

_thread_locals = local()

class CustomerDatabaseRouter:
    def db_for_read(self, model, **hints):
        # 返回当前线程绑定的客户数据库
        return getattr(_thread_locals, 'current_customer_db', 'default')

    def db_for_write(self, model, **hints):
        return self.db_for_read(model, **hints)

    def allow_relation(self, obj1, obj2, **hints):
        # 允许同一数据库内的关联操作
        return obj1._state.db == obj2._state.db

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        # 只在对应客户数据库执行迁移
        return db == getattr(_thread_locals, 'current_customer_db', 'default')
  • 在settings.py中注册路由:
DATABASE_ROUTERS = ['myproject.db_router.CustomerDatabaseRouter']
  • 新增中间件绑定客户标识到线程:
class CustomerMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 从域名解析客户(比如customer_a.example.com -> customer_a)
        host_parts = request.get_host().split('.')
        customer_id = host_parts[0] if len(host_parts) >=3 else 'default'
        
        # 绑定到线程局部变量
        _thread_locals.current_customer_db = customer_id
        
        response = self.get_response(request)
        return response
  • 在settings.py的MIDDLEWARE中添加这个中间件。

3. 部署方案

多进程/容器模式(推荐)

每个客户启动独立的Django进程(或Docker容器),共享同一代码目录,通过环境变量指定客户:

  • 用Gunicorn启动示例:
# 启动客户A的服务
CUSTOMER_ID=customer_a gunicorn myproject.wsgi:application --bind 127.0.0.1:8000

# 启动客户B的服务
CUSTOMER_ID=customer_b gunicorn myproject.wsgi:application --bind 127.0.0.1:8001
  • 用Nginx做反向代理,根据域名路由到对应进程:
server {
    server_name customer_a.example.com;
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # 直接处理静态文件,减轻Django压力
    location /customer_a/static/ {
        root /path/to/your/static/files;
    }
}

server {
    server_name customer_b.example.com;
    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    location /customer_b/static/ {
        root /path/to/your/static/files;
    }
}

单进程多客户模式(适合小型场景)

用上面的数据库路由+中间件方案,单进程处理所有客户请求,通过域名区分,无需多进程,但要注意进程隔离和性能问题。

4. 客户新增与代码维护

  • 新增客户:
    1. 创建对应数据库并授权
    2. 在configs目录新增客户配置文件
    3. 启动对应进程(多进程模式)或重启单进程
    4. 执行迁移:CUSTOMER_ID=new_customer python manage.py migrate
  • 代码变更:
    直接更新主代码目录,重启所有客户进程即可,所有客户自动同步新代码,无需逐个修改。

注意事项

  • 数据库权限严格隔离,每个客户的数据库账号仅能访问自己的库
  • 可编写自动化脚本(如create_customer.py)批量完成配置创建、数据库初始化、迁移操作
  • 日志按客户拆分,方便排查问题:
# settings.py 日志配置
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'customer_file': {
            'class': 'logging.FileHandler',
            'filename': f'/var/log/django/{CUSTOMER_ID}.log',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['customer_file'],
            'level': 'INFO',
            'propagate': True,
        },
    },
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{',
        },
    },
}

内容的提问来源于stack exchange,提问作者andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:07:31