[关闭]
@StrGlee 2016-10-20T10:49:19.000000Z 字数 1958 阅读 1223

SAE 中 Flask Blueprint 指定 template folder 无效问题分析

之前的 解决 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

  1. IOError: Permission denied: /data1/www/htdocs/562/greatghoul/1/templates/index.html

如果你建立一个空的 templates 目录,flask 便不会报错了,不过这还是不能解决模板搜索路径优先级的问题。

我们先看下下 flask 对于优先级的处理:

  1. class DispatchingJinjaLoader(BaseLoader):
  2. """A loader that looks for templates in the application and all
  3. the blueprint folders.
  4. """
  5. # ...
  6. def _iter_loaders(self, template):
  7. loader = self.app.jinja_loader
  8. if loader is not None:
  9. yield loader, template
  10. # old style module based loaders in case we are dealing with a
  11. # blueprint that is an old style module
  12. try:
  13. module, local_name = posixpath.normpath(template).split('/', 1)
  14. blueprint = self.app.blueprints[module]
  15. if blueprint_is_module(blueprint):
  16. loader = blueprint.jinja_loader
  17. if loader is not None:
  18. yield loader, local_name
  19. except (ValueError, KeyError):
  20. pass
  21. for blueprint in self.app.blueprints.itervalues():
  22. loader = blueprint.jinja_loader
  23. if loader is not None:
  24. yield loader, template

通过代码可以看出来,搜索顺序为 app -> module(不推荐使用) -> 各blurprint ,给人的感觉是,blueprint 的模板设置,就像 皇宫的二线嫔妃一样,正宫娘娘享受完了皇帝,才有她们的份。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注