如何基于单数据库创建路径区分的Django 3多站点?
Django 3 单域名多子路径共库站点部署最佳实践
整个方案基于单项目多APP架构实现,不需要部署多个Django实例,维护成本最低,完全匹配子路径访问、共库、公共内容复用的需求。
1. 项目结构拆分
- 根路径主站点单独创建
coreAPP承载,每个子路径站点(website1到websiteN)分别独立创建对应APP,比如web1、web2,后续新增站点直接新建APP即可 - 所有跨站点复用的公共能力(公共模型、模板组件、工具函数、静态资源、通用视图)全部抽离到独立的
commonAPP中,禁止把公共代码散落在各个站点APP里 - 所有APP统一注册到
INSTALLED_APPS列表,共用同一份settings配置,不需要维护多套配置文件
共库注意事项:所有模型统一迁移到同一个数据库,不需要配置多数据库路由。公共表(用户表、全局配置、公共内容块等)全部放在
commonAPP下生成迁移文件,各站点独有模型放在自身APP下生成迁移文件,统一执行python manage.py makemigrations和python manage.py migrate即可,只要不同APP的模型不重名就不会出现表冲突。
2. 路由配置(核心匹配规则)
直接在项目根路由表中按路径前缀挂载各个站点的路由即可,注意路由顺序,避免子站请求被主站兜底路由拦截:
# 项目根目录urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # 先挂载所有子站点路由 path('website1/', include('web1.urls')), path('website2/', include('web2.urls')), # 新增子站只需要在这里加一行对应路由即可 # path('website_n/', include('webn.urls')), # 最后挂载主站路由 path('', include('core.urls')), ]
注意:子站点APP内部的路由全部写相对路径即可,比如web1中配置path('about/', about_view),实际访问路径就是main_domain.com/website1/about/,不需要在子APP路由里重复写website1前缀。
3. 公共内容复用实现
分四个层面落地,完全避免重复开发:
- 公共数据复用:公共模型(通用文章、广告位、友链、全局配置等)全部定义在
commonAPP的models.py中,各站点直接导入调用即可,不需要重复建表。可以给公共模型加site_tag字段,标记内容是全站点通用还是归属某个子站,各站点按需过滤数据即可。 - 公共模板复用:在项目根目录创建统一的
templates目录,内部按common(公共页头、页脚、导航、分页组件等片段)、core(主站模板)、web1/web2(子站模板)分子目录,在TEMPLATES配置中把根templates目录加入DIRS列表,子站模板直接通过{% include 'common/header.html' %}引入公共片段即可,公共模板预留block块支持子站做差异化覆盖。 - 公共静态资源复用:根目录创建统一的
static目录,内部按common(公共css、js、图片、字体)、core、web1/web2分子目录存放资源,模板中引用公共资源直接写{% static 'common/css/global.css' %}即可,不需要每个站点重复存储一份公共资源。 - 公共逻辑复用:通用登录校验、列表分页逻辑、文件上传能力、异常处理等全部写在
commonAPP的utils.py或者通用视图中,各站点直接导入调用、或继承通用视图即可,不需要重复编写相同逻辑。
4. 部署与站点识别方案
- 部署层面只需要启动一个Django进程(搭配Gunicorn/uWSGI均可),Nginx把所有请求统一转发给该进程,静态资源执行
python manage.py collectstatic统一收集到同一个目录由Nginx托管,不需要为每个子路径单独配置转发或静态资源规则。 - 子站点差异化配置识别不需要引入Django自带的sites框架(该框架适配多域名场景,当前场景用反而增加复杂度),自己写一个轻量中间件即可实现当前站点配置注入:
# common/middleware.py # 维护各站点的差异化配置,比如站点名、备案号、logo路径等 SITE_MAPPING = { '': {'site_name': '主站', 'icp': '京ICP备xxx号-1'}, 'website1': {'site_name': '站点1', 'icp': '京ICP备xxx号-2'}, 'website2': {'site_name': '站点2', 'icp': '京ICP备xxx号-3'}, } class SiteIdentifyMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 提取请求路径第一段作为站点匹配标识 path_prefix = request.path.strip('/').split('/')[0] # 绑定当前站点配置到request对象,所有视图、模板可直接调用 request.current_site = SITE_MAPPING.get(path_prefix, SITE_MAPPING['']) return self.get_response(request)
写完把该中间件加入settings的MIDDLEWARE列表即可生效。
后续新增子站点的流程非常固定:新建对应APP→编写站点独有逻辑和模板→根路由添加一行挂载配置→在站点映射字典中加对应差异化配置,最快十几分钟就能完成一个新站上线,公共能力直接复用不需要重复开发。
内容的提问来源于stack exchange,提问作者Darwin
相关产品推荐
相关产品推荐

