How to serve static files in Flask
In production, configure the HTTP server (Nginx, Apache, etc.) in front of your application to serve requests to /static
from the static folder. A dedicated web server is very good at serving static files efficiently, although you probably won't notice a difference compared to Flask at low volumes.
Flask automatically creates a /static/<path:filename>
route that will serve any filename
under the static
folder next to the Python module that defines your Flask app. Use url_for
to link to static files: url_for('static', filename='js/analytics.js')
You can also use send_from_directory
to serve files from a directory in your own route. This takes a base directory and a path, and ensures that the path is contained in the directory, which makes it safe to accept user-provided paths. This can be useful in cases where you want to check something before serving the file, such as if the logged in user has permission.
from flask import send_from_directory
@app.route('/reports/<path:path>')
def send_report(path):
return send_from_directory('reports', path)
Do not use send_file
or send_static_file
with a user-supplied path. This will expose you to directory traversal attacks. send_from_directory
was designed to safely handle user-supplied paths under a known directory, and will raise an error if the path attempts to escape the directory.
If you are generating a file in memory without writing it to the filesystem, you can pass a BytesIO
object to send_file
to serve it like a file. You'll need to pass other arguments to send_file
in this case since it can't infer things like the file name or content type.
Flask: How to serve static html?
Reducing this to the simplest method that'll work:
- Put static assets into your
static
subfolder. - Leave Flask set to the default, don't give it a
static_url_path
either. - Access static content over the pre-configured
/static/
to verify the file works
If you then still want to reuse a static file, use current_app.send_static_file()
, and do not use leading /
slashes:
from flask import Flask, current_app
app = Flask(__name__)
@app.route('/')
def hello_world():
return current_app.send_static_file('editor.html')
This looks for the file editor.html
directly inside the static
folder.
This presumes that you saved the above file in a folder that has a static
subfolder with a file editor.html
inside that subfolder.
Some further notes:
static_url_path
changes the URL static files are available at, not the location on the filesystem used to load the data from.render_template()
assumes your file is a Jinja2 template; if it is really just a static file then that is overkill and can lead to errors if there is actual executable syntax in that file that has errors or is missing context.
How to serve static site with flask
We can consider MkDocs's rendered HTML pages as simple Flask templates. So all we have to do is to create a Flask endpoint that first do the permissions-checking then based on the URL, serves the rendered MkDocs HTML file or a related static file.
Let's call our new endpoint bridge
. First, put everything from MkDocs site
directory to Flask's templates/bridge
directory. My example MkDocs tree looks like this:
$ tree templates/bridge
templates/bridge
├── 404.html
├── css
│ ├── base.css
│ ├── bootstrap.min.css
│ └── font-awesome.min.css
├── dir1
│ ├── sub1
│ │ └── index.html
│ └── sub2
│ └── index.html
├── dir2
│ ├── sub1
│ │ └── index.html
│ └── sub2
│ └── index.html
├── fonts
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── img
│ ├── favicon.ico
│ └── grid.png
├── index.html
├── js
│ ├── base.js
│ ├── bootstrap.min.js
│ └── jquery-1.10.2.min.js
├── search
│ ├── lunr.js
│ ├── main.js
│ ├── search_index.json
│ └── worker.js
├── sitemap.xml
└── sitemap.xml.gz
And our new Flask bridge
endpoint:
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
@app.route('/bridge/')
@app.route('/bridge/<path:p1>/')
@app.route('/bridge/<path:p1>/<path:p2>/')
@app.route('/bridge/<path:p1>/<path:p2>/<path:p3>/')
def bridge(p1=None, p2=None, p3=None):
# Permissions checking...
# Serve MkDocs's static files requested from CSS files
if p1 == 'css' and p2 in ('img', 'fonts'):
# CSS fix, e.g. /bridge/css/img/example.png -> /bridge/img/example.png
return send_from_directory(f'templates/bridge/{p2}/', p3)
# Serve MkDocs's static files
if p1 in ('css', 'js', 'fonts', 'search'):
return send_from_directory(f'templates/bridge/{p1}/', p2)
# Serve rendered MkDocs HTML files
if p3 != None:
template = f'bridge/{p1}/{p2}/{p3}/index.html'
elif p2 != None:
template = f'bridge/{p1}/{p2}/index.html'
elif p1 != None:
template = f'bridge/{p1}/index.html'
else:
template = 'bridge/index.html'
return render_template(template)
As you see we created a couple of path definitions. Since MkDocs uses relative paths everywhere, the URL path dir1/sub1/
in MkDocs will become https://yoursite.com/bridge/dir1/sub1/
so we can catch them with this URL routing scheme and the URL parts will land into p1
, p2
, p3
path variables that we will use to serve the corresponding content.
There are two types of content: static files (e.g. CSS files or images) and HTML content files. The static files will be in the css
, js
, images
, fonts
, etc. directory, so when p1
equals one of these we use Flask's send_from_directory
function to serve them. Static files referenced from CSS files need to have a specific treatment because MkDocs uses relative paths there as well.
And for the rendered index.html
files we just need to determine the nesting level based on the path and return the selected index.html
file as a normal Flask template. Since MkDocs uses relative URLs we don't have to modify anything in the rendered HTML files, every URL will receive the /bridge/
prefix, so we can serve them with our bridge
endpoint.
You should do the permissions checking at the beginning of bridge
(or as a decorator, depending your solution). You may need to add p4
and/or p5
path variables if you have more deeply nested content, but it's a straightforward extension of my example.
Note: the 404 error page will be also served by Flask.
How to properly server static files from a Flask server?
Pass these arguments when you initialise the app:
app = Flask(__name__, static_folder='public',
static_url_path='frontend_public' )
This would make the file public/blah.txt
available at http://example.com/frontend_public/blah.txt
.
static_folder
sets the folder on the filesystemstatic_url_path
sets the path used within the URL
If neither of the variables are set, it defaults to 'static'
for both.
Hopefully this is what you're asking.
How to send a file from a network drive in Flask
All static files must be in static
folder. Some oprions you have:
- Copy the files that are elsewhere on your filesystem into that folder
- Add some code to your server script that copies the files from their origin to the static files folder
- Put your server script on your external drive, so your static folder is on that drive, and run it from there. If you need to serve content from several folders on that drive you might be able to create shortcuts to those folders under
static
folder but I can't test right now , on Windows I doubt this will work (on Linux very likely that symbolic links would work). - You could have one flask app running for each different folder where you have static content, listening on a different port. Those apps would all be identical. Your HTML served by your main app would have links with those ports.
- Find where in the source flask looks for the source folder, and extend by a few lines of code to be able to look in other folders.
- Use
flask.send_file
andflask.send_file_from_directory
: as long as your database contains a mapping of file ID's to file paths, and you put the file ID's in the HTML served to client, then when client requests the file, your flask app uses the ID in the URL to determine file location and usesflask.send_file_from_directory
to serve the file. - You might also be able to use Flask Blueprints since each blueprint can have its own static folder
Serving static files from static folder with Flask
If you have audio files in the static
folder you can access them in templates using url_for
as like other static files. Documentation of serving static files can be found in this URL.
Here I am showing an example of getting audio files URL in templates. I have passed the list of files from Flask app to the templates.
Directory structure:
├── app.py
├── static
│ ├── demo1.mp3
│ ├── demo2.mp3
│ └── demo3.mp3
└── templates
├── audio.html
app.py
:
from flask import Flask, render_template
app = Flask(__name__, static_folder='static')
@app.route('/')
def index():
audio_files = ["demo1.mp3", "demo2.mp3", "demo3.mp3"]
return render_template('audio.html', audio_files=audio_files)
audio.html
:
<!DOCTYPE html>
<html>
<head>
<title>Audio Example</title>
</head>
<body>
<h2>Serving audio files from Flask</h2>
{% for file in audio_files %}
<audio controls>
<source src={{ url_for('static', filename=file) }} type="audio/mpeg">
</audio>
{% endfor %}
<p>Click on play icon to play</p>
</body>
</html>
Output:
Cannot Serve Static Files
Ended up being I set the UPLOAD_FOLDER directory to
UPLOAD_FOLDER = '/profile_pictures'
Where it should've been
UPLOAD_FOLDER = 'profile_pictures'
Thanks for the answer @ Alexander : )
Flask app can't load CSS file from static folder
I've figured out the solution. I just needed to add the following to my __init__.py
file:
package_dir = os.path.dirname(
os.path.abspath(__file__)
)
static = os.path.join(
package_dir, "static"
)
app.static_folder=static
Related Topics
Checking If Element Exists With Python Selenium
Run Multiple Python Scripts Concurrently
How to Listen For 'Usb Device Inserted' Events in Linux, in Python
Splitting Out the Output of Ps Using Python
Why Is the Command Bound to a Button or Event Executed When Declared
Of the Many Findelement(S)/By Functions in Selenium, When Would You Use One Over the Other
What Exactly Do "U" and "R" String Prefixes Do, and What Are Raw String Literals
Unboundlocalerror on Local Variable When Reassigned After First Use
How to List All Files of a Directory
How to Sort a List of Dictionaries by a Value of the Dictionary
What's the Easiest Way to Escape HTML in Python
How to Find the Real User Home Directory Using Python
How to Use "/" (Directory Separator) in Both Linux and Windows in Python
Force Another Program'S Standard Output to Be Unbuffered Using Python
How to Select Rows from a Dataframe Based on Column Values
What Is the Meaning of Single and Double Underscore Before an Object Name