How to serve static files in Flask

Posted on

Solving problem is about exposing yourself to as many situations as possible like How to serve static files in Flask and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about How to serve static files in Flask, which can be followed any time. Take easy to follow this discuss.

How to serve static files in Flask

So this is embarrassing. I’ve got an application that I threw together in Flask and for now it is just serving up a single static HTML page with some links to CSS and JS. And I can’t find where in the documentation Flask describes returning static files. Yes, I could use render_template but I know the data is not templatized. I’d have thought send_file or url_for was the right thing, but I could not get those to work. In the meantime, I am opening the files, reading content, and rigging up a Response with appropriate mimetype:

import os.path
from flask import Flask, Response
app = Flask(__name__)
app.config.from_object(__name__)
def root_dir():  # pragma: no cover
    return os.path.abspath(os.path.dirname(__file__))
def get_file(filename):  # pragma: no cover
    try:
        src = os.path.join(root_dir(), filename)
        # Figure out how flask returns static files
        # Tried:
        # - render_template
        # - send_file
        # This should not be so non-obvious
        return open(src).read()
    except IOError as exc:
        return str(exc)
@app.route('/', methods=['GET'])
def metrics():  # pragma: no cover
    content = get_file('jenkins_analytics.html')
    return Response(content, mimetype="text/html")
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def get_resource(path):  # pragma: no cover
    mimetypes = {
        ".css": "text/css",
        ".html": "text/html",
        ".js": "application/javascript",
    }
    complete_path = os.path.join(root_dir(), path)
    ext = os.path.splitext(path)[1]
    mimetype = mimetypes.get(ext, "text/html")
    content = get_file(complete_path)
    return Response(content, mimetype=mimetype)
if __name__ == '__main__':  # pragma: no cover
    app.run(port=80)

Someone want to give a code sample or url for this? I know this is going to be dead simple.

Answer #1:

The preferred method is to use nginx or another web server to serve static files; they’ll be able to do it more efficiently than Flask.

However, you can use send_from_directory to send files from a directory, which can be pretty convenient in some situations:

from flask import Flask, request, send_from_directory
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')
@app.route('/js/<path:path>')
def send_js(path):
    return send_from_directory('js', path)
if __name__ == "__main__":
    app.run()

Do not use send_file or send_static_file with a user-supplied path.

send_static_file example:

from flask import Flask, request
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')
@app.route('/')
def root():
    return app.send_static_file('index.html')
Answered By: hughdbrown

Answer #2:

If you just want to move the location of your static files, then the simplest method is to declare the paths in the constructor. In the example below, I have moved my templates and static files into a sub-folder called web.

app = Flask(__name__,
            static_url_path='',
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path='' removes any preceding path from the URL (i.e.
    the default /static).
  • static_folder='web/static' to serve any files found in the folder
    web/static as static files.
  • template_folder='web/templates' similarly, this changes the
    templates folder.

Using this method, the following URL will return a CSS file:

<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">

And finally, here’s a snap of the folder structure, where flask_server.py is the Flask instance:

Nested Static Flask Folders

Answered By: atupal

Answer #3:

You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.

app = Flask(__name__, static_url_path='/static')

With that set you can use the standard HTML:

<link rel="stylesheet" type="text/css" href="/static/style.css">
Answered By: Richard Dunn

Answer #4:

I’m sure you’ll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files

Basically you just need a “static” folder at the root of your package, and then you can use url_for('static', filename='foo.bar') or directly link to your files with http://example.com/static/foo.bar.

EDIT: As suggested in the comments you could directly use the '/static/foo.bar' URL path BUT url_for() overhead (performance wise) is quite low, and using it means that you’ll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).

Answered By: sharpshadow

Answer #5:

You can use this function :

send_static_file(filename)
Function used internally to send static
files from the static folder to the browser.

app = Flask(__name__)
@app.route('/<path:path>')
def static_file(path):
    return app.send_static_file(path)
Answered By: b4stien

Answer #6:

What I use (and it’s been working great) is a “templates” directory and a “static” directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask’s templating syntax. Below is a sample call in my views.py file.

@app.route('/projects')
def projects():
    return render_template("projects.html", title = 'Projects')

Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You’ll probably end up doing this anyways in your CSS/JS file links in html. For instance…

<script src="{{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>

Here’s a link to the “canonical” informal Flask tutorial – lots of great tips in here to help you hit the ground running.

http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

Answered By: BlackMamba

Answer #7:

A simplest working example based on the other answers is the following:

from flask import Flask, request
app = Flask(__name__, static_url_path='')
@app.route('/index/')
def root():
    return app.send_static_file('index.html')
if __name__ == '__main__':
  app.run(debug=True)

With the HTML called index.html:

<!DOCTYPE html>
<html>
<head>
    <title>Hello World!</title>
</head>
<body>
    <div>
         <p>
            This is a test.
         </p>
    </div>
</body>
</html>

IMPORTANT: And index.html is in a folder called static, meaning <projectpath> has the .py file, and <projectpath>static has the html file.

If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')

EDIT: For showing all files in the folder if requested, use this

@app.route('/<path:path>')
def static_file(path):
    return app.send_static_file(path)

Which is essentially BlackMamba‘s answer, so give them an upvote.

Answered By: Kyle Sum

Answer #8:

For angular+boilerplate flow which creates next folders tree:

backend/
|
|------ui/
|      |------------------build/          <--'static' folder, constructed by Grunt
|      |--<proj           |----vendors/   <-- angular.js and others here
|      |--     folders>   |----src/       <-- your js
|                         |----index.html <-- your SPA entrypoint
|------<proj
|------     folders>
|
|------view.py  <-- Flask app here

I use following solution:

...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")
@app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
    return send_from_directory(root, path)
@app.route('/', methods=['GET'])
def redirect_to_index():
    return send_from_directory(root, 'index.html')
...

It helps to redefine ‘static’ folder to custom.

Answered By: EpicPandaForce

Leave a Reply

Your email address will not be published.