Now Reading
How to use Blueprint static folders correctly in Python – Flask
0

How to use Blueprint static folders correctly in Python – Flask

by Simon ParkerApril 26, 2020

In a sentence. Static folders don’t inherit as templates do. Ill explain.

In Flask you have a concept called Blueprints.

In most Flask tutorials you see throughout the web they will have a single file which contains everything including your routes, models and any other code. You may do some includes to pull in additional functions but that is probably it.

As your Flask application grows in size this is obviously not feasible and the different sections of code need to be separated out into different folders or separations of concerns as it were.

For this, you can use Blueprints. you create a folder for example /lists/ and in there you define an __init__.py file or similar that will contain the instructions for this blueprint.

from flask import Blueprint

blueprint = Blueprint(
'lists_blueprint',
__name__,
url_prefix='/lists',
template_folder='templates',
static_folder='static'
)

This isn’t a full Blueprints tutorial and if you want to learn more about Blueprints then either go here, here or here

What I wanted to discuss is how to make proper use of the static folder within the blueprint, as you can see above we define the static folder, to contain our css and js files for example, as being “static”

So in the nature of blueprints you would then expect the path to this folder to be /lists/static as we are defining a prefix and then defining a static folder location.

So if we add a template into the lists template folder and use something like

<link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet" />

We might expect the URL to be /lists/static/css/custom.css

However this does not happen. we just get the main static folder from the base blueprint at /static and of course, the file does not exist there.

There are a few different options here. They differ slightly from templates files which I will explain below in more detail.

The simplest solution is to add a location to the static folder by using either .  or the blueprint name

<link href="{{ url_for('.static', filename='css/custom.css') }}" rel="stylesheet" />
<link href="{{ url_for('lists_blueprint.static', filename='css/custom.css') }}" rel="stylesheet" />

There are quite a few conversations around the internet on the use of the static_url_path variable that can be included in the blueprint definition like so

from flask import Blueprint

blueprint = Blueprint(
‘lists_blueprint’,
__name__,
url_prefix=’/lists’,
template_folder=’templates’,
static_folder=’static’,
static_url_path=’/lists/static’
)

If you add this static_url_path line you would again expect any templates or other content within the blueprint to work but if you are using templates then you still have to define the static location and using

 <link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet" />

will result in the same issues as before with it looking in the main static folder for the app and not the blueprints static folder.
using

<link href="{{ url_for('lists_blueprint.static', filename='css/custom.css') }}" rel="stylesheet" />

Will now give you the path /lists/lists/static/css/custom.css because it is adding in the additional static url path as well as the blueprint prefix.

Perhaps this approach might be useful if you have several blueprints which register at the root of the site but when using prefixes this approach seems pointless.

So the correct and simplest solution seems to be you do not include a static url path in the blueprint definition and when making a template you simply add the . to the start of the static folder in order to use the static folder within the blueprint you are currently active in.

A note about templates vs static folders.

Template folders are created within Blueprints in the same way however, and I think this is where the confusion starts, template folders will search within blueprint template folders if the template is not found in the main static folder.

So if you have a template in your lists blueprint called lists.html the Flask app will first look in the main static folder for lists.html and, if it does not find it, will then search in the Blueprints folder for the template.

This inheritance in the templates means there is some confusion over why the static folder doesnt work in the same way.

It also gives rise to a sensible approach when making templates to include a subfolder matching the blueprint name in your templates folder.

So my lists template is in /app/lists/templates/lists/lists.html

Note the additional /lists/ after the template folder.

This prevents accidental overwrites in the main templates folder if you happen to have another lists.html file there.

You see this approach used quite often in various tutorials but it never really gets explained properly and I think half the issue there is the confusion around inheritance versus static folders.

So to summarise.

Static folders don’t inherit.

Add the proper link to them using url_for and then either blueprint name.static or just .static works well for me and seems the simplest solution.

 

What's your reaction?
Love It
0%
Interested
0%
Meh...
0%
What?
0%
Hate It
0%
Sad
0%
About The Author
Simon Parker

Leave a Response