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

如何通过默认数据库的Tenant模型填充Django多租户的connections列表?

实现方案

1. 完善Tenant模型

首先扩展你的Tenant模型,补充数据库连接所需的核心字段,同时添加方法生成符合Django数据库配置格式的字典:

from django.db import models

class Tenant(models.Model):
    name = models.CharField(max_length=20)
    # 数据库连接基础信息
    db_name = models.CharField(max_length=100)
    db_user = models.CharField(max_length=50)
    db_password = models.CharField(max_length=100)
    db_host = models.CharField(max_length=100, default='localhost')
    db_port = models.CharField(max_length=10, default='5432')  # 根据你的数据库类型调整,比如MySQL用3306

    def get_db_config(self):
        """返回符合DATABASES结构的配置字典"""
        return {
            'ENGINE': 'django.db.backends.postgresql',  # 替换为你的数据库引擎,如django.db.backends.mysql
            'NAME': self.db_name,
            'USER': self.db_user,
            'PASSWORD': self.db_password,
            'HOST': self.db_host,
            'PORT': self.db_port,
        }

2. 动态加载租户数据库配置到DATABASES

在项目启动阶段,从default数据库读取所有租户数据,将它们的数据库配置自动注入到Django的settings.DATABASES中。可以在主应用的apps.py中实现:

from django.apps import AppConfig
from django.conf import settings
from django.db import connections
from .models import Tenant
import sys

class MainAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'main_app'  # 替换为你的应用名称

    def ready(self):
        # 仅在运行服务或shell时执行,避免migrate等初始化命令报错
        if 'runserver' in sys.argv or 'shell' in sys.argv:
            tenants = Tenant.objects.all()
            for tenant in tenants:
                # 添加租户数据库配置
                settings.DATABASES[tenant.name] = tenant.get_db_config()
                # 刷新connections池,使新配置立即生效
                connections._connections.pop(tenant.name, None)

记得在应用的__init__.py中指定自定义的AppConfig:

default_app_config = 'main_app.apps.MainAppConfig'

3. 动态切换租户数据库(可选)

如果需要根据请求自动切换到对应租户的数据库,可编写中间件实现。这里以子域名识别租户为例,你可以根据实际场景替换为请求头、Session等方式:

from django.db import connections, router
from .models import Tenant

class TenantMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 从子域名提取租户名称,如 tenant1.yourdomain.com -> tenant1
        host_parts = request.get_host().split('.')
        if len(host_parts) >= 3:
            tenant_name = host_parts[0]
            try:
                tenant = Tenant.objects.get(name=tenant_name)
                # 切换当前数据库连接
                connections['default'].close()
                request.tenant = tenant
                # 覆盖路由规则,让ORM操作指向租户数据库
                router.db_for_read = lambda model, **hints: tenant.name
                router.db_for_write = lambda model, **hints: tenant.name
            except Tenant.DoesNotExist:
                # 租户不存在时的处理,比如返回404
                pass

        response = self.get_response(request)
        # 请求结束后关闭租户数据库连接
        if hasattr(request, 'tenant'):
            connections[request.tenant.name].close()
        return response

将中间件添加到settings.MIDDLEWARE中:

MIDDLEWARE = [
    # ... 其他中间件
    'main_app.middleware.TenantMiddleware',
]

4. 批量迁移租户数据库

由于每个租户有独立数据库,需要批量执行迁移。编写自定义管理命令:

from django.core.management.base import BaseCommand
from django.core.management import call_command
from main_app.models import Tenant

class Command(BaseCommand):
    help = '执行所有租户数据库的迁移操作'

    def handle(self, *args, **options):
        tenants = Tenant.objects.all()
        for tenant in tenants:
            self.stdout.write(f"正在迁移租户 {tenant.name} 的数据库...")
            call_command('migrate', database=tenant.name, **options)
        self.stdout.write(self.style.SUCCESS("所有租户数据库迁移完成"))

运行命令即可批量迁移:

python manage.py migrate_all_tenants

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 04:32:27