You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在Apache虚拟主机中使用不同的Flask模板目录

实现Flask按VirtualHost切换模板的方案

嘿,这个需求我之前也帮人处理过,其实Flask里实现起来挺灵活的,结合你已经搞定的静态资源切换,咱们把模板这块也搞定,不用复制整个代码树~

先理清楚目录结构

首先建议你把不同风格的模板分开存放,比如:

your_flask_app/
├── app.py
├── templates/          # 默认白色风格模板
│   ├── base.html
│   └── index.html
├── templates_red/      # 红色风格模板(只放和默认不同的文件就行)
│   ├── base.html
│   └── index.html
├── static/             # 默认静态资源
└── static_red/         # 红色风格静态资源(你已经配置好Apache了)

这样红色模板只需要修改和默认不一样的部分,不用全量复制,节省维护成本。

方法一:视图函数里动态指定模板路径(简单直接,适合少量视图)

如果你的视图不多,可以直接在每个视图里判断请求的Host,然后指定对应模板的路径:

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/')
def index():
    # 匹配红色域名
    if request.host == 'red.mysite.com':
        # 加载templates_red下的模板,注意路径是相对当前模板根目录的上层
        return render_template('../templates_red/index.html')
    else:
        # 默认加载templates下的模板
        return render_template('index.html')

这种方法的优点是上手快,缺点是视图多的话要重复写判断逻辑,不够优雅。

方法二:自定义模板加载器(推荐,适合多视图场景)

Flask的模板加载由jinja_loader管理,我们可以自定义一个加载器,让它自动根据当前Host优先查找对应风格的模板目录,找不到再用默认的。这样所有视图都不用改,直接用原来的render_template就行。

代码示例:

from flask import Flask, request
from jinja2 import ChoiceLoader, FileSystemLoader

app = Flask(__name__)

# 配置域名和模板目录的映射,以后加新风格直接在这里加就行
HOST_TEMPLATE_MAP = {
    'red.mysite.com': 'templates_red',
    # 比如以后加蓝色风格:'blue.mysite.com': 'templates_blue'
}

def get_custom_template_loader():
    # 获取当前请求的Host
    current_host = request.host
    # 准备加载器列表:先加对应域名的模板目录,再加默认目录
    loaders = []
    if current_host in HOST_TEMPLATE_MAP:
        loaders.append(FileSystemLoader(HOST_TEMPLATE_MAP[current_host]))
    # 始终添加默认模板目录作为 fallback
    loaders.append(FileSystemLoader('templates'))
    # 返回组合加载器,会按顺序查找模板
    return ChoiceLoader(loaders)

# 每次请求前更新模板加载器
@app.before_request
def setup_template_loader():
    app.jinja_loader = get_custom_template_loader()

# 视图函数完全不用改,正常写就行
@app.route('/')
def index():
    # 加载器会自动找对应域名的模板,找不到就用默认的
    return render_template('index.html')

这种方法的好处是一劳永逸,不管以后加多少视图或者新的风格,只需要在HOST_TEMPLATE_MAP里加新的映射就行,代码扩展性极强。

额外优化:模板继承减少重复代码

红色风格的模板不用全量复制默认模板,用Jinja2的继承特性只改差异部分就行。比如红色的base.html可以这样写:

{% extends "../templates/base.html" %}

{% block page_style %}
<!-- 只替换红色风格的CSS -->
<link rel="stylesheet" href="/static_red/style.css">
{% endblock %}

{% block page_title %}
红色风格站点
{% endblock %}

这样公共部分(比如导航栏、页脚)都复用默认模板的,只改需要定制的部分,维护起来超省心。

注意事项

  • 确保Apache的所有VirtualHost都指向同一个Flask应用(比如同一个WSGI脚本),这样Flask才能拿到请求的Host头进行判断。
  • 如果是泛域名(比如*.mysite.com),可以通过提取子域名来匹配模板目录,比如:
    current_subdomain = request.host.split('.')[0]
    # 假设子域名red对应templates_red
    if current_subdomain in ['red', 'blue']:
        loaders.append(FileSystemLoader(f'templates_{current_subdomain}'))
    
  • 如果不想依赖Apache的静态资源配置,也可以在Flask里通过上下文处理器动态生成静态资源URL,比如:
    @app.context_processor
    def inject_static_helper():
        def static_path(filename):
            if request.host == 'red.mysite.com':
                return f'/static_red/{filename}'
            else:
                return f'/static/{filename}'
        return dict(static=static_path)
    
    然后在模板里用{{ static('style.css') }}引用静态资源,Flask会自动切换路径。

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

火山引擎 最新活动