How To Change Static Assets Defaults in Flask

By Adam McQuistan in Python  06/26/2019 Comment

Introduction

This How To demonstrates changing the default static directory and url path in a Python Flask application to a url /public along with a public assets directory. I recently needed to do this in a Flask app that is primarily a REST API behind a JavaScript SPA frontend because the Vue.js SPA was already using a /static path. I didn't really want to intermingle the assets I was working with and, for the admin like UI I wanted to keep it simple utilizing only Flask and Jinja templates. I also wanted to be able to use the url_for template helper so, changing the static directory and url path was simple solution for my use case.

Demo Flask Application

To best demonstrate this concept I will be building a very minimal Flask app that serves one template that displays an image, The Coding Interface's logo.

Kicking things off I have a very basic Flask application with the following file structure.

$ tree . -I venv
.
├── app.py
├── static
│   └── images
│       └── tci.png
└── templates
    └── index.html

Inside app.py is a Flask app instance which serves a single index.html template from the root / url path.

from flask import Flask, render_template

app = Flask('flaskapp')

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

Then index.html is simply the contents of an h1 with a message and an image of the The Coding Interface's logo as seen below.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Flask Rocks!</title>
</head>
<body>
  <h1>Flask Rocks!</h1>
  <div>
    <img id='image' style="width: 90%; margin: auto;" src="{{ url_for('static', filename='images/tci.png') }}" alt="The Coding Interface">
  </div>
</body>
</html>

As you can see the image is sourced using the handy url_for template helper along with the 'static' argument and filename specifying the asset being requested.

Changing the Url Path

Ok, above is the demo app with default settings for serving static content (an image in this case) from the default static directory and referenced in an HTTP request to the /static url. Recall that the problem I am trying to solve is to utilize a different url path other than /static to reference by Flask specific assets. It turns out the official Flask docs specify that the static url path is configurable using the 'static_url_path' parameter to the Flask application initializer.

 

This means simply changing this line in app.py

app = Flask('flaskapp')

to include the static_url_path set to something useful like /public will do the trick.

app = Flask('flaskapp', static_url_path='/public')

And voila, problem solved!

What was /static path ...

Flask static url path

 

is now a /public path :)

Flask public path

 

However, at first it wasn't entirely clear to me if I would need to update the template code which uses 'static' in the url_for(...) method call

url_for('static', filename='images/tci.png') 

to something like

url_for('public', filename='images/tci.png') 

It turns out the 'static' parameter is just there to indicate that the url should be constructed for a static asset and not a view function.

If for consistency sake I were to want to actually change the name of the directory from static to public (which I did) that is as simple as adding another initializer parameter of static_folder shown below.

app = Flask('flaskapp', static_url_path='/public', static_folder='public')

Plus, of course, renaming the static directory to public.

Changes to Deployment Server

To make this work in a deployment environment like a Linux server utilizing Nginx to reverse proxy to a suitable Python application server like Gunicorn or uWSGI is similarly a simple change to the Nginx server block config. All that is needed is a server location setup to point to the public directory on the server as shown below.

server {
  listen 80;
  server_name example.com;

  location /favicon.ico { access_log off; log_not_found off; }

  # path to the previously utilized 
  # static directory by the SPA app
  location /static/ {
    root /path/to/spa-app;
  }

  # path to the flask app's new
  # public directory
  location /public {
    root /path/to/flask-app
  }

  location / {
    include proxy_params;
    proxy_pass http://unix:/path/to/flaskapp.sock;
  }
}

Learn More About this Topic

Conclusion

At theCodingInterface.com, "How To..." articles are short code snippet-like content pieces that are generally accompanied with only brief explanations focusing on the use of code to convey a specific topic. This How To focussed on how to change the default url path and directory for a Flask application's static assets. For more detailed explanations please have a look at the referenced material linked within the Learn More About this Topic section.

As always, thanks for reading and don't be shy about commenting or critiquing below.

Share with friends and colleagues

[[ likes ]] likes

Community favorites for Python

theCodingInterface