此文章主要是为了记录在使用 Flask 的过程当中遇到的问题。本章主要讨论 render_template 函数的问题。
使用 Flask 的同窗都应该知道,项目中的 url 和视图函数是在字典里一一对应着的,再详细一点,就是 url 对应着 endpoint,视图函数也对应着 endpoint,而且 endpoint 在字典里是惟一存在的。css
而对于不一样 Blueprint 里的 url,是依靠所注册的蓝图以及不一样的前缀来进行区分。可是在视图函数中所调用的 render_template 函数可得不到 endpoint 的支持,若是你使用的不一样目录下的同样命名的模板文件,那么就会出现问题了。html
先摆事实、再讲道理。python
实例项目的目录结构以下:flask
app ├── admin │ ├── errors.py │ ├── forms.py │ ├── __init__.py │ ├── static │ │ ├── css │ ├── templates │ │ ├── index.html │ ├── views.py ├── __init__.py ├── main │ ├── errors.py │ ├── forms.py │ ├── __init__.py │ ├── templates │ │ └── ousi │ │ ├── index.html │ │ ├── static │ │ │ ├── css │ ├── views.py ├── models.py
该项目中注册两个 Blueprint,即 admin 是所谓的后台管理蓝图,main 是所谓的前台展现蓝图。
蓝图 admin 的 __init__.py 内容以下:app
# -*- coding:utf-8 -*- __author__ = '东方鹗' from flask import Blueprint admin = Blueprint('admin', __name__, template_folder="templates", static_folder='static') # 在末尾导入相关模块,是为了不循环导入依赖,由于在下面的模块中还要导入蓝本main from . import views, errors
蓝图 main 的 __init__.py 内容以下:函数
# -*- coding:utf-8 -*- __author__ = '东方鹗' from flask import Blueprint main = Blueprint('main', __name__, template_folder="templates/ousi", static_folder='templates/ousi/static') # 在末尾导入相关模块,是为了不循环导入依赖,由于在下面的模块中还要导入蓝本main from . import views, errors
在定义两个蓝图的时候,也对本蓝图所对应的模板文件夹和静态文件夹进行了定义,此文主要关注模板文件夹。测试
那么,如今就说说出现了什么问题。ui
在各自蓝图的视图函数中都对主页 '/' 或叫作 'index' 进行了定义。url
其中,蓝图 admin 的视图函数定义以下:code
@admin.route('/', methods=['GET', 'POST']) @login_required def index(): return render_template('index.html')
请记住最后的代码,即 render_template('index.html')
,此处调用的模板名叫作 index.html
。
蓝图 admin 的视图函数定义以下:
@main.route('/', methods=['GET', 'POST']) def index(): return render_template('index.html')
请记住最后的代码,即 render_template('index.html')
,此处调用的模板名叫作 index.html
。
到此,你发现了什么,你发现了什么,我估计你已经看出来两个视图函数的最后一行代码是同样的,说得再精确点,调用的模板名是同样的。可是此处咱们要保持清醒,虽然模板名称同样,可是所在目录是不同的,它们所处的位置是各自所在的蓝图所定义的模板文件夹里。
说了这么多,到底怎么了呢。
这时,若是你测试一下你的程序的话,你会发现两个蓝图所显示的内容是同样的,无论你相信不相信本身的眼睛,它就是同样的界面,并且绝对同样,由于 render_template('index.html')
调用的是同一个模板,它可不会区分蓝图。
那么,到底调用的是那个蓝图下的模板呢??继续往下看。
这时你打开 app/__init__.py,内容以下:
def create_app(config_name): """ 使用工厂函数初始化程序实例""" app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app=app) # mail.init_app(app=app) moment.init_app(app=app) db.init_app(app=app) md.init_app(app=app) login_manager.init_app(app=app) # 注册蓝本 main from .main import main as main_blueprint app.register_blueprint(main_blueprint, url_prefix='/main') # 注册蓝本 admin from .admin import admin as admin_blueprint app.register_blueprint(admin_blueprint, url_prefix='/admin') # 注册蓝本 main #from .main import main as main_blueprint #app.register_blueprint(main_blueprint, url_prefix='/dynamic') return app
到底调用的是那个蓝图下的模板呢??
这个,我能够明确告诉你,main 和 admin 两个蓝图,哪一个在 app/__init__.py 中先注册,就调用那个蓝图的模板,也就是说哪一个蓝图注册时所用的代码写得靠上,就调用那个蓝图的模板。
这究竟是为何呢?为何呢?这是 flask 项目的一个小 bug。写项目的时候,要注意此坑,render_template()
函数里所调用的模板必定要保证命名在整个项目中的惟一性。
今天又发现了一个坑,就是 jinja2 内部的模板调用,好比 include 某某模板的时候,这个被调用的模板名称也须要,并且强烈须要保证在整个项目,记住是整个项目中,其命名要具备惟一性。