flask的蓝图模板的覆盖问题

发表于:2018-06-20 23:35:27
更新于:2018-06-20 23:35:27

笔者在开发开源项目“myblog”的时候,遇到了蓝图模板“被覆盖”的问题。 现在整理成文章,如果你被同样的问题困扰,也能这篇文章能帮上忙。

正文

实验环境: win10、Python3.6.5、Flask1.0.2

项目结构如下:

/app
    /manage.py
    /main
        /views.py
        /templates
            index.html    
    /admin
        /views.py
        /templates 
            index.html   

/app/main/views.py内容如下:

from flask import Blueprint, render_template
main = Blueprint('main', __name__, template_folder='templates')
@main.route('/')
def index():
    return render_template('index.html')

/app/admin/views.py内容如下:

from flask import Blueprint, render_template
admin = Blueprint('admin', __name__, template_folder='templates', url_prefix='/admin')
@admin.route('/')
def index():
    return render_template('index.html')

/app/manage.py内容如下:

from flask import Flask
from app.main import main
from app.admin import admin

def create_app():
    app = Flask(__name__)
    app.register_blueprint(main)
    app.register_blueprint(admin)
    return app

在cmd中输入flask run(执行前记得设置FLASK_APP、FLASK_DEBUG)。待程序跑起来后,在浏览器 地址栏中输入127.0.0.1:5000,显示的是main蓝图的inde.html。输入127.0.0.1/admin/, 显示的还是 main蓝图的index.html。奇怪,这是为什么呢?笔者在网上搜索了半天,最终在flask官方的 github上找到了相关issue,感兴趣的朋友可以看看。 Method render_template does not use blueprint specified template_folder #1361

此外,官方的文档中也有相关说明(Templates 部分):blueprint-resources
为了方便日后查看,这里翻译成了中文,并对一些地方进行了补充。

对于文章开头的例子,我开启了flask的EXPLAIN_TEMPLATE_LOADING,再次访问 127.0.0.1:5000的时候,在cmd窗口中会有如下输出:

[2018-05-19 22:06:21,488] INFO in debughelpers: Locating template "index.html":
    1: trying loader of application "flask_server.app"
       class: jinja2.loaders.FileSystemLoader
       encoding: 'utf-8'
       followlinks: False
       searchpath:
         - D:\app\templates
       -no match
    2: trying loader of blueprint "main" (flask_server.main)
       class: jinja2.loaders.FileSystemLoader
       encoding: 'utf-8'
       followlinks: False
       searchpath:
         - D:\app\main\templates
       -found ('D:\\app\\main\\templates\\index.html')
    3: trying loader of blueprint "admin" (flask_server.admin)
       class: jinja2.loaders.FileSystemLoader
       encoding: 'utf-8'
       followlinks: False
       searchpath:
         - D:\app\admin\templates
       -found ('D:\\app\\admin\\templates\\index.html')
Warning: multiple loaders returned a match for the template.
  The template was looked up from an endpoint that belongs to the blueprint "main".
  Maybe you did not place a template in the right folder?
  See http://flask.pocoo.org/docs/blueprints/#templates
127.0.0.1 - - [19/May/2018 22:06:21] "GET / HTTP/1.1" 200 -

根据官方给出的建议,尝试修改项目的结构以及相关代码:

更改后的项目结构如下:
/app
    /manage.py
    /main
        /views.py
        /templates
            /main
                /index.html    
    /admin
        /views.py
        /templates
            /admin 
                index.html   

/app/main/views.py内容如下:

from flask import Blueprint, render_template
main = Blueprint('main', __name__, template_folder='templates')
@main.route('/')
def index():
    return render_template('main/index.html')  # 修改后

/app/admin/views.py内容如下:

from flask import Blueprint, render_template
admin = Blueprint('admin', __name__, template_folder='templates', url_prefix='/admin')
@admin.route('/')
def index():
    return render_template('admin/index.html')  # 修改后

再次执行flask run(执行前记得设置FLASK_APP、FLASK_DEBUG),访问127.0.0.1:5000127.0.0.1:5000/admin,发现原来“被覆盖”的html页面已经能被正确地对应上了。