@StrGlee
2016-10-20T18:49:19.000000Z
字数 1958
阅读 1341
之前的 解决 SAE 中 Flask Blueprint 指定 template folder 无效问题 的方案中,是使用 render_template_string() 间接 实现 render_template(),但是这一方案有一个很大的缺陷,就是会丢失 jinja 模板的一些特性,比如继承,include 等一些 相关路径的操作,而且还要手动处理编码问题。
在 flask 的邮件列表中,有一个比较细致的讨论 Templates for blueprints 以及 SO 中的规避的方案:
Two options come to mind.
Rename each of the index.html files to be unique (e.g. admin.html and main.html).
In each of the template folders, put each of the templates in a subdirectory of the blueprint folder and then call the template using that subdirectory. Your admin template, for example, would be yourapp/admin/pages/admin/index.html, and then called from within the blueprint as render_template('admin/index.html').
其实在官方的文档中描述的也很明确:
The template folder is added to the searchpath of templates but with a lower priority than the actual application’s template folder.
模板目录会添加到模板搜索路径中,但是相比于 app 的模板目录, 它的优先级比较低。
在 blueprint 中请求 render_template() 时,flask 会优先搜索 app 的 template_folder 下的模板, 如果找不到,再到其它路径中找。
这个过程在 SAE 中会出一个问题:app 的 template_folder 不存在,那 SAE 在访问默认 template_dir,也就是 templates 目录时,会如 nkchenz 所言,报一个IOError。
比如我的应用根目录中根本 templates 文件夹,SAE 在试图访问 ..../greatghoul/1/templates/index.html 时,就会 IOError
IOError: Permission denied: /data1/www/htdocs/562/greatghoul/1/templates/index.html
如果你建立一个空的 templates 目录,flask 便不会报错了,不过这还是不能解决模板搜索路径优先级的问题。
我们先看下下 flask 对于优先级的处理:
class DispatchingJinjaLoader(BaseLoader):
"""A loader that looks for templates in the application and all
the blueprint folders.
"""
# ...
def _iter_loaders(self, template):
loader = self.app.jinja_loader
if loader is not None:
yield loader, template
# old style module based loaders in case we are dealing with a
# blueprint that is an old style module
try:
module, local_name = posixpath.normpath(template).split('/', 1)
blueprint = self.app.blueprints[module]
if blueprint_is_module(blueprint):
loader = blueprint.jinja_loader
if loader is not None:
yield loader, local_name
except (ValueError, KeyError):
pass
for blueprint in self.app.blueprints.itervalues():
loader = blueprint.jinja_loader
if loader is not None:
yield loader, template
通过代码可以看出来,搜索顺序为 app -> module(不推荐使用) -> 各blurprint ,给人的感觉是,blueprint 的模板设置,就像 皇宫的二线嫔妃一样,正宫娘娘享受完了皇帝,才有她们的份。