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.

+3


source to share


2 answers


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.

+2


source


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

0


source







All Articles