基于django-tenent-scheme创建独立租户管理门户的技术咨询
基于django-tenant-schemas实现独立租户管理门户的方案
不需要新建独立项目,完全可以在现有django-tenant-schemas项目内实现不与租户共享的管理门户,核心是区分主域名(门户)和子域名(租户)的路由逻辑,解决你之前门户在所有租户可见的问题。以下是具体实现步骤:
1. 配置域名识别与路由分离
django-tenant-schemas默认通过public租户处理公共内容,但我们可以通过自定义中间件,根据请求域名切换不同的URL配置:
1.1 编写域名识别中间件
在项目中创建中间件文件(比如middleware/tenant_domain_middleware.py):
from django.conf import settings from django.urls import set_urlconf class DomainRoutingMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 提取不带端口的域名 host = request.get_host().split(':')[0] # 判断是否是主门户域名 if host == settings.MAIN_PORTAL_DOMAIN: # 加载公共门户的URL配置 set_urlconf('your_project.public_urls') else: # 加载租户专属的URL配置 set_urlconf('your_project.tenant_urls') response = self.get_response(request) return response
1.2 配置settings.py
- 添加主域名常量:
MAIN_PORTAL_DOMAIN = "myapp.net"
- 将自定义中间件加入中间件列表(注意要放在
django_tenants.middleware.main.TenantMainMiddleware之后):
MIDDLEWARE = [ # ...其他中间件 'django_tenants.middleware.main.TenantMainMiddleware', 'your_project.middleware.tenant_domain_middleware.DomainRoutingMiddleware', # ...其他中间件 ]
1.3 分离路由文件
- 创建
public_urls.py:存放门户相关路由(注册、账户管理、许可证购买等),示例:
from django.urls import path from .views import portal_home, client_register, account_management urlpatterns = [ path('portal/', portal_home, name='portal_home'), path('portal/register/', client_register, name='client_register'), path('portal/account/', account_management, name='account_management'), # ...其他门户路由 ]
- 创建
tenant_urls.py:存放租户专属的业务路由,示例:
from django.urls import path from .tenant_views import tenant_dashboard, tenant_profile urlpatterns = [ path('', tenant_dashboard, name='tenant_dashboard'), path('profile/', tenant_profile, name='tenant_profile'), # ...其他租户业务路由 ]
2. 实现门户的租户创建逻辑
在公共视图中处理客户注册,直接操作Tenant和Domain模型创建新租户,示例:
from django.shortcuts import render, redirect from django_tenants.models import Tenant, Domain from .forms import ClientRegistrationForm def client_register(request): if request.method == 'POST': form = ClientRegistrationForm(request.POST) if form.is_valid(): # 创建租户(schema名称要符合数据库规范,建议小写、无特殊字符) tenant_schema = form.cleaned_data['client_name'].lower().replace(' ', '_') tenant = Tenant.objects.create( name=form.cleaned_data['client_name'], schema_name=tenant_schema, # 可添加其他自定义字段,比如许可证类型 license_type=form.cleaned_data['license_type'] ) # 创建租户对应的子域名 Domain.objects.create( tenant=tenant, domain=f"{tenant_schema}.myapp.net", is_primary=True ) # 注册完成后跳转至租户登录页或门户首页 return redirect('portal_home') else: form = ClientRegistrationForm() return render(request, 'portal/register.html', {'form': form})
3. DNS与服务器配置
不需要分开部署服务器,只需要将主域名和泛域名指向同一服务器IP:
myapp.netA记录 -> 你的服务器IP*.myapp.netA记录 -> 你的服务器IP
如果用Nginx做反向代理,配置示例如下:
server { listen 80; server_name myapp.net *.myapp.net; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
关键注意事项
- 门户的视图和路由仅在主域名下生效,子域名请求会加载租户专属路由,不会看到
/portal路径 - 所有门户操作都在
publicschema下执行,不需要切换租户上下文,避免与租户数据混淆 - 若之前已将门户放在租户路由中,需彻底移除相关代码,确保仅在
public_urls.py中定义门户路由
内容的提问来源于stack exchange,提问作者Mrugała Tomasz
相关产品推荐
相关产品推荐

