Flask: Template in Blueprint Inherit from Template in App?

Hephaestus

I'm a total Flask/Jinja2 newbie, so maybe I'm overlooking something obvious, but:

Shouldn't Flask, out of the box, allow a template that exists in a blueprint's templates/ folder to extend a base template defined by my app's templates/ folder? Shouldn't this work even if the blueprint also includes a "default" base template, which I override by defining my own base template of the same name?

The answer to this other SO question makes me think that both of those things should absolutely be the case. Specifically the part of the answer that says:

If there are two templates with same name[, one] in app's templates folder and [the other in] blueprint's template folder, then template in app's templates folder will get priority.

But it's not working that way at all for me. In fact, it seems to work the opposite way, i.e., the base.html from the blueprint is being pulled in by pages defined in my app, even though my app defines its own base.html (which should "get priority" if the above answer is correct).

In my app I have:

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

where pages/home_page extends pages/page_base, which in turn extends base.

I'm also using the flask_user package from PyPI, which was installed (by pip) at /usr/local/lib/python2.7/dist-packages/flask_user/. Its templates folder is arranged 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 via a Blueprint which it establishes with the following calls in the init_app function of its UserManager class (__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'd be able to customize pages rendered from templates in flask_user/templates/flask_user/ to look like other pages in my app, because (per the referenced answer) my base.html should take precedence over flask_user's base.html.

But that's not working, and what's worse -- and much more surprising -- is that my app's pages are being given the default look of flask_user's pages.

Digging Deeper...

Looking into @Pralhad Narsinh Sonar's suggestion that there may be a problem with the ordering of the template search paths, possibly caused by non-deterministic behavior of DispatchingJinjaLoader._iter_loaders() as suggested in the fewstreet.com article he cited, I did a quick experiment to see what ordering _iter_loaders() would produce for my app:

>>> 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 yields the loader for my app's templates/ folder first, before yielding the loader for flask_user/templates/. In fact, the _iter_loaders() function is quite deliberately structured to return the app's loader before returning any Blueprints' loaders. (If I'm reading the fewstreet.com article correctly, the problem it's concerned with is non-deterministic ordering among multiple Blueprints, which -- since there's only one Blueprint being used by my app -- isn't my current problem.)

This result makes it even harder for me to understand why flask_user's base.html template is being used to resolve my template's {% extends "base.html" %} statement*. Given that I have my own base.html file in myapp/templates, I see no reason whatsoever for the templating system to look at anything in flask_user/templates to render myapp/templates/pages/home_page.html.

* For testing purposes I got rid of the indirection through pages/page_base.html mentioned above.

So: Obviously something else is going wrong, but what?

I haven't yet grokked enough of the relevant code in flask/templating.py or jinja2/loaders.py to understand why and how this might be happening. This being my first foray into Flask, I would have hoped I wouldn't need to.

Hephaestus

And the answer is:

All this time I've been running (and reloading) my app with debug=True.

Which is great for automatically reloading changed Python modules.

But for changed templates? Um... not so much.

After introducing a breakpoint into my home_page.html template and using the Flask debugger to look back through a few stack frames, I discovered that Jinja2 makes use of an LRU cache to store (by name) templates it has already parsed.

Because I had hatched the idea of creating my own base.html template after having already loaded a flask_user page (login.html), which had originally inherited from flask_user/templates/base.html, there was already a template named base.html in the cache by the time I introduced myapp/templates/base.html.

So I stopped and restarted the app, and now both my home_page.html and flask_user's login.html are correctly inheriting from my base.html instead of from flask_user's base.html. I suspect that before I power-cycled the app, my own base.html had never even been read by my app's template loader.

This is a fairly significant -- and, I believe, undocumented -- gotcha for a newbie to have to figure out. I'll just leave this here, in hopes that it someday helps someone else who happens to step into this particular trap.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Java

flask blueprint template folder

From Dev

How to run Flask app by flask run with blueprint template

From Dev

Flask - render template in other Blueprint without redirect

From Dev

Inherit from class template nested in template argument

From Dev

Importing from main app in a flask blueprint

From Dev

Inherit from classes passed to constructor as a template parameters an inherit from them

From

Inherit from const type passed as template parameter

From Dev

Template specialisation inherit from specific subclass

From Dev

c++ inherit from a template struct

From Dev

How can a template class inherit from a nested template class

From Java

Reload Flask app when template file changes

From Java

Reload Flask app when template file changes

From Dev

Flask app is running correct function, but not rendering template

From Dev

Conversion in template from Classes inherit a base class to base

From Dev

How to recursively inherit a template class from itself? (not CRTP!)

From Dev

Python template, is there a way to inherit from multiple html files?

From Dev

Can you instantiate the unspecialized version of a template and inherit from it inside the specialization?

From Dev

Is it legal for class template specialisations to inherit from different base classes?

From Dev

ng2 inherit from component and extend parent template

From Dev

Inherit from non-specialized template (shared library)

From Dev

Backbone.js template does not inherit attributes from model

From Dev

How to pass argument from template to view in Flask

From Dev

How to send data from flask to html template

From Dev

passing an argument from flask template to view

From Dev

Display image from MySQL in Flask template

From Dev

Flask Redirect From Jinja HTML Template

From Dev

Pass JSON data from Flask to JavaScipt in the template

From Dev

Ordering query data from html template in flask

From Dev

How to pass HTML string from flask app to HTML template as a DOM element and then appendChild

Related Related

  1. 1

    flask blueprint template folder

  2. 2

    How to run Flask app by flask run with blueprint template

  3. 3

    Flask - render template in other Blueprint without redirect

  4. 4

    Inherit from class template nested in template argument

  5. 5

    Importing from main app in a flask blueprint

  6. 6

    Inherit from classes passed to constructor as a template parameters an inherit from them

  7. 7

    Inherit from const type passed as template parameter

  8. 8

    Template specialisation inherit from specific subclass

  9. 9

    c++ inherit from a template struct

  10. 10

    How can a template class inherit from a nested template class

  11. 11

    Reload Flask app when template file changes

  12. 12

    Reload Flask app when template file changes

  13. 13

    Flask app is running correct function, but not rendering template

  14. 14

    Conversion in template from Classes inherit a base class to base

  15. 15

    How to recursively inherit a template class from itself? (not CRTP!)

  16. 16

    Python template, is there a way to inherit from multiple html files?

  17. 17

    Can you instantiate the unspecialized version of a template and inherit from it inside the specialization?

  18. 18

    Is it legal for class template specialisations to inherit from different base classes?

  19. 19

    ng2 inherit from component and extend parent template

  20. 20

    Inherit from non-specialized template (shared library)

  21. 21

    Backbone.js template does not inherit attributes from model

  22. 22

    How to pass argument from template to view in Flask

  23. 23

    How to send data from flask to html template

  24. 24

    passing an argument from flask template to view

  25. 25

    Display image from MySQL in Flask template

  26. 26

    Flask Redirect From Jinja HTML Template

  27. 27

    Pass JSON data from Flask to JavaScipt in the template

  28. 28

    Ordering query data from html template in flask

  29. 29

    How to pass HTML string from flask app to HTML template as a DOM element and then appendChild

HotTag

Archive