我是一个完整的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_app
类UserManager
类 # 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.html
或flask/templating.py
中的相关代码,以了解为何以及如何发生这种情况。这是我第一次涉足Flask,我希望我不需要。
答案 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.html
和flask_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