Flask:蓝图中的模板是否继承自应用程序中的模板?

时间:2015-06-20 19:37:41

标签: python templates flask jinja2

我是一个完整的Flask / Jinja2新手,所以也许我忽略了一些明显的东西,但是:

开箱即用的Flask不应该允许蓝图的templates/文件夹中存在的模板扩展我应用的templates/文件夹定义的基本模板吗?即使蓝图还包含一个“默认”基本模板,我不应该这样做,我通过定义我自己的同名基本模板来覆盖它?

this other SO question的答案让我觉得这两件事情都应该是这样的。特别是答案的一部分说:

  

如果app的模板文件夹中有两个名称相同的模板[,一个],而蓝图的模板文件夹中有另一个模板,那么app的模板文件夹中的模板将获得优先权。

但它对我来说根本不是这样。实际上,它似乎与相反的方式有效,即蓝图中的base.html被我应用中定义的页面拉入,即使我的应用程序定义了自己的base.html(如果上述答案正确,应该“优先”)。

在我的应用中,我有:

myapp/
   templates/
       base.html
       pages/
           page_base.html
           home_page.html

其中pages/home_page扩展pages/page_base,后者又扩展base

我也在使用PyPI的flask_user包,它是pip)在/usr/local/lib/python2.7/dist-packages/flask_user/安装的。其templates文件夹的排列如下:

flask_user/
    templates/
        base.html
        flask_user/
            [templates that extend base.html]

此软件包使其模板可供通过蓝图使用的模板使用,该蓝图通过其init_appUserManager # Add flask_user/templates directory using a Blueprint blueprint = Blueprint('flask_user', 'flask_user', template_folder='templates') app.register_blueprint(blueprint) 函数中的以下调用建立:{/ 3}}: p>

myapp/templates/base.html

我最初的想法是,通过定义我自己的flask_user/templates/flask_user/,我可以自定义从base.html中的模板呈现的页面,使其看起来像我的应用程序中的其他页面,因为(根据引用的答案)我的flask_user应优先于base.html的{​​{1}}。

但这不起作用,更糟糕的是 - 更令人惊讶的是,我的应用程序的页面被赋予了flask_user页面的默认外观。

深入挖掘......

调查@Pralhad Narsinh Sonar的建议,模板搜索路径的排序可能存在问题,可能是由DispatchingJinjaLoader._iter_loaders()的{​​{1}}的非确定性行为引起的,如他引用的__init__.py, line 154所示,我做了一个快速实验,看看_iter_loaders()为我的应用程序产生的排序:

>>> from myapp.top import app, db
>>> from myapp.startup import init_app.init_app
>>> init_app(app, db)
>>> app.jinja_env.loader
<flask.templating.DispatchingJinjaLoader object at 0x7f233e396dd0>
>>> for loader in app.jinja_env.loader._iter_loaders('pages/home_page.html') :
...   print loader, loader.searchpath
... 
<jinja2.loaders.FileSystemLoader object at 0x7f233eb08490> ['/var/www/python/myapp/templates']
<jinja2.loaders.FileSystemLoader object at 0x7f233e36ef10> ['/usr/local/lib/python2.7/dist-packages/flask_user/templates']

正如预期的那样,在为templates/生成加载器之前,迭代器会为我的应用程序的flask_user/templates/文件夹首先生成的加载器。实际上,_iter_loaders()函数是非常有意识地构造的,以便在返回任何 Blueprints'加载器之前返回应用程序的加载器。 (如果我正确地阅读了这篇文章,那么它关注的问题是多个蓝图中的非确定性排序,因为我的应用程序只使用了一个蓝图 - isn这是我目前的问题。)

这个结果让我更难理解为什么flask_user的{​​{1}}模板用于解析我的模板的base.html声明*。鉴于我在{% extends "base.html" %}中拥有自己的base.html文件,我认为模板系统没有理由查看myapp/templates中的任何内容以呈现flask_user/templates

*出于测试目的,我通过上面提到的myapp/templates/pages/home_page.html摆脱了间接。

所以:显然其他东西出了问题,但是什么

我还没有充分了解pages/page_base.htmlflask/templating.py中的相关代码,以了解为何以及如何发生这种情况。这是我第一次涉足Flask,我希望我不需要。

2 个答案:

答案 0 :(得分:2)

答案是:

此时我一直在使用debug=True运行(并重新加载)我的应用。

这对于自动重新加载已更改的Python模块非常有用。

但是对于已更改的模板?嗯......不是那么多。

在我的home_page.html模板中引入断点并使用Flask调试器回顾几个堆栈帧后,我发现Jinja2使用LRU缓存来存储(按名称)已解析的模板。

因为我已经在已经加载了base.html页面(flask_user)之后创建了我自己的login.html模板的想法,该页面最初是从flask_user/templates/base.html,在我介绍base.html时,已经已经在缓存中名为myapp/templates/base.html的模板。

所以我停止并重新启动应用,现在我的home_page.htmlflask_user的{​​{1}}都正确地继承自我的 login.html而不是来自base.html的{​​{1}}。我怀疑在我重新启动应用程序之前,我自己的flask_user从未被我的应用程序的模板加载器读取

这是一个相当重要的 - 我相信,无证件 - 让新手必须弄明白。我会把它留在这里,希望有一天能帮助其他碰巧进入这个特定陷阱的人。

答案 1 :(得分:0)

如果您可以分享代码的blueprint部分,将会非常有帮助。

这可能是搜索路径出现故障的结果 - 其中它将第一行模板视为要显示的模板。为避免这种情况,您始终可以唯一地重命名模板文件。如果您想保留相同的名称,如果有任何限制或偏好,那么您可以尝试将模板文件保存在主模板文件夹的子目录下。

您可以浏览此链接 - http://flask.pocoo.org/docs/0.10/blueprints/

选项#1

请尝试使用此文件夹结构 - 您还需要在blueprints -

中进行更改
myapp/
----templates/
--------base.html
--------pages/
------------page_base.html
------------home_page.html
----flask_user/
--------pages/
------------flask_user
----------------page_base.html
----------------home_page.html

更深入了解烧瓶中的这个问题 - http://fewstreet.com/2015/01/16/flask-blueprint-templates.html

选项#2

myapp/
----templates/
--------base.html
--------pages/
------------page_base.html
------------home_page.html
--------flask_user
------------page_base.html
------------home_page.html
--------module_1
------------page_base.html
------------home_page.html
--------module_2
------------page_base.html
------------home_page.html
----flask_user/ # --> this is a module
-------- another module functionality
----module_1/ # --> this is a module
-------- another module functionality
----module_2/ # --> this is a module
-------- another module functionality

在上面的结构中,每个模块都有自己的路由文件,即 - view.py,因此单独的blueprint配置使每个功能模块化。

请查看https://www.digitalocean.com/community/tutorials/how-to-structure-large-flask-applications