Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

render_template from Flask blueprint uses other blueprint's template

Tags:

python

flask

I have a Flask app with blueprints. Each blueprint provides some templates. When I try to render the index.html template from the second blueprint, the first blueprint's template is rendered instead. Why is blueprint2 overriding blueprint1's templates? How can I render each blueprint's templates?

app/
    __init__.py
    blueprint1/
        __init__.py
        views.py
        templates/
            index.html
    blueprint2/
        __init__.py
        views.py
        templates/
            index.html

blueprint2/__init__.py:

from flask import Blueprint

bp1 = Blueprint('bp1', __name__, template_folder='templates', url_prefix='/bp1')

from . import views

blueprint2/views.py:

from flask import render_template
from . import bp1

@bp1.route('/')
def index():
    return render_template('index.html')

app/__init__.py:

from flask import Flask
from blueprint1 import bp1
from blueprint2 import bp2

application = Flask(__name__)
application.register_blueprint(bp1)
application.register_blueprint(bp2)

If I change the order the blueprints are registered, then blueprint2's templates override blueprint1's.

application.register_blueprint(bp2)
application.register_blueprint(bp1)
like image 269
koc Avatar asked Jul 06 '16 09:07

koc


1 Answers

This is working exactly as intended, although not as you expect.

Defining a template folder for a blueprint only adds the folder to the template search path. It does not mean that a call to render_template from a blueprint's view will only check that folder.

Templates are looked up first at the application level, then in the order blueprints were registered. This is so that an extension can provide templates that can be overridden by an application.

The solution is to use separate folders within the template folder for templates related to specific blueprints. It's still possible to override them, but much harder to do so accidentally.

app/
    blueprint1/
        templates/
            blueprint1/
                index.html
    blueprint2/
        templates/
            blueprint2/
                index.html

Point each blueprint at its templates folder.

bp = Blueprint('bp1', __name__, template_folder='templates')

When rendering, point at the specific template under the templates folder.

render_template('blueprint1/index.html')

See Flask issue #1361 for more discussion.

like image 177
davidism Avatar answered Nov 15 '22 13:11

davidism