Flask: template in Blueprint Inherit from template in app?
I'm a complete Flask / Jinja2 newbie, so maybe I'm missing something obvious, but:
Shouldn't the checkbox, out of the box, allow a template that exists in the project folder templates/
to extend the base template defined by my application folder templates/
? Should this work even though the project also has a default base template that I override by defining my own base template with the same name?
The answer to this other SO question makes me think that both of these things should be exactly the same. Specifically, the part of the answer that reads:
If there are two templates with the same name [, one] in the application templates folder and there are two templates in the templates folder [in another], then the template in the application templates folder will take precedence.
But it doesn't work at all for me. In fact, it works the other way around, i.e. base.html
from the drawing is pulled in by the pages defined in my application, although my application defines its own base.html
(which should "get priority" if the above answer is correct).
In my application I have:
myapp/
templates/
base.html
pages/
page_base.html
home_page.html
where pages/home_page
continues pages/page_base
, which in turn continues base
.
I am also using a package flask_user
from PyPI that was installed ( pip
) in /usr/local/lib/python2.7/dist-packages/flask_user/
. Its templates folder is organized as follows:
flask_user/
templates/
base.html
flask_user/
[templates that extend base.html]
This package makes its templates available to applications that use it through the Blueprint, which it installs with the following calls in init_app
its class function UserManager
( __init__.py
, line 154 ):
# Add flask_user/templates directory using a Blueprint
blueprint = Blueprint('flask_user', 'flask_user', template_folder='templates')
app.register_blueprint(blueprint)
My initial thinking was that by defining my own myapp/templates/base.html
, I could customize the pages generated from templates in flask_user/templates/flask_user/
to look like other pages in my application, because (for the answer referenced by) my base.html
should take precedence over flask_user
base.html
.
But that doesn't work, and what's worse - and more surprising - is that the pages in my application are presented with a standard page view flask_user
.
Digging deeper ...
Looking at @Pralhad Narsinh Sonar, suppose there might be a problem with the ordering of pattern search paths, possibly caused by non-deterministic behavior DispatchingJinjaLoader._iter_loaders()
as suggested in the article fewstreet.com , he cited, I did a quick experiment to see what ordering _iter_loaders()
would do for my application:
>>> 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']
As expected, the iterator issues a loader for my application templates/
first, before yielding a loader for flask_user/templates/
. In fact, the function is _iter_loaders()
quite deliberately structured to return the application loader before returning the Blueprints loaders. (If I read the somestreet.com article correctly, the problem it poses is non-deterministic ordering among multiple blueprints, which - since there is only one Blueprint used in my application - is not my current problem.)
This result makes it even more difficult for me to understand why the pattern is being flask_user
base.html
used to resolve my {% extends "base.html" %}
statement * pattern . Given that I have my own base.html
file in myapp/templates
, I see no reason for the templating system to be able flask_user/templates
to render anything myapp/templates/pages/home_page.html
.
* For testing purposes, I got rid of the indirection through the pages/page_base.html
one mentioned above.
So: Obviously something else is going wrong, but what?
I have not yet received enough relevant code in flask/templating.py
or jinja2/loaders.py
to understand why and how this might be happening. This was my first foray into Flask, I would have hoped I didn't need it.
source to share
And the answer is:
All the while, I was starting (and reloading) my application with debug=True
.
This is great for automatically reloading modified Python modules.
But for changed templates? Hmm ... not much.
After injecting a breakpoint into my template home_page.html
and using Flask debug to look at multiple stack frames, I found that Jinja2 uses the LRU cache to store (by name) the templates it has already parsed.
Since I started the idea of ββcreating my own template base.html
after having already loaded the page flask_user
( login.html
) that it originally inherited from flask_user/templates/base.html
, there was already a named template base.html
in the cache by the time I entered myapp/templates/base.html
.
So I stopped and restarted the app and now mine home_page.html
and flask_user
login.html
correctly inherit from mine base.html
, not from flask_user
base.html
. I suspect that before I enabled the app, my own was base.html
never read by my app template loader.
This is a fairly significant - and undocumented, I suppose - to get a newbie to figure out. I'll just leave this here in the hopes that it will someday help someone else who falls into this particular pitfall.
source to share
It will be extremely helpful if you can share a section of blueprint
your code.
This could be the result of a failure in the search path - in which it treats the first line pattern as displayable. To avoid this, you can always rename the template files unambiguously. If, for any limitation or preference, if you want to keep the same names, try saving the template files in subdirectories of the main templates folder.
You can go through this link - http://flask.pocoo.org/docs/0.10/blueprints/
Option number 1
Try using this folder structure - you also need to make changes to blueprints
-
myapp/
----templates/
--------base.html
--------pages/
------------page_base.html
------------home_page.html
----flask_user/
--------pages/
------------flask_user
----------------page_base.html
----------------home_page.html
More light on this issue in flask - http://fewstreet.com/2015/01/16/flask-blueprint-templates.html
Option number 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
In the structure above, each module will have its own ie routes file - view.py
and therefore separate configurations blueprint
to keep each functionality modular.
Please have a look at https://www.digitalocean.com/community/tutorials/how-to-structure-large-flask-applications
source to share