Static files in Flask – robot.txt, sitemap.xml (mod_wsgi)

Question:

Is there any clever solution to store static files in Flask’s application root directory.
robots.txt and sitemap.xml are expected to be found in /, so my idea was to create routes for them:

@app.route('/sitemap.xml', methods=['GET'])
def sitemap():
  response = make_response(open('sitemap.xml').read())
  response.headers["Content-type"] = "text/plain"
  return response

There must be something more convenient đŸ™‚

Asked By: biesiad

||

Answers:

Serving static files has nothing to do with application that is meant to deliver dynamic content. The correct way of serving static files is dependent of what server you’re using. After all, when you get your app up and running, you will need to bind it to a web server. I can speak only for apache httpd, so the way of serving static files is defined in the virtual host that you are binding to your application through mod-wsgi. Here is the guide that will show you how to serve sitemaps, robots.txt or any static content:
http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_At_Root_Of_Site

Answered By: vonPetrushev

@vonPetrushev is right, in production you’ll want to serve static files via nginx or apache, but for development it’s nice to have your dev environment simple having your python app serving up the static content as well so you don’t have to worry about changing configurations and multiple projects. To do that, you’ll want to use the SharedDataMiddleware.

from flask import Flask
app = Flask(__name__)
'''
Your app setup and code
'''
if app.config['DEBUG']:
    from werkzeug import SharedDataMiddleware
    import os
    app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
      '/': os.path.join(os.path.dirname(__file__), 'static')
    })

This example assumes your static files are in the folder “static”, adjust to whatever fits your environment.

Answered By: Philip Southam

From the documentation here: http://flask.pocoo.org/docs/quickstart/#static-files

Dynamic web applications need static
files as well. That’s usually where
the CSS and JavaScript files are
coming from. Ideally your web server
is configured to serve them for you,
but during development Flask can do
that as well. Just create a folder
called static in your package or next
to your module and it will be
available at /static on the
application.

To generate URLs to that part of the
URL, use the special ‘static’ URL
name:

url_for(‘static’,
filename=’style.css’)

The file has to be stored on the
filesystem as static/style.css.

Answered By: Josh Klein

This might have been added since this question was asked, but I was looking through flask’s “helpers.py” and I found flask.send_from_directory:

send_from_directory(directory, filename, **options)
'''
  send_from_directory(directory, filename, **options)
  Send a file from a given directory with send_file.  This
  is a secure way to quickly expose static files from an upload folder
  or something similar.
'''

… which references flask.send_file:

send_file(filename_or_fp, mimetype=None, as_attachment=False, attachment_filename=None, add_etags=True, cache_timeout=43200, conditional=False)

… which seems better for more control, although send_from_directory passes **options directly through to send_file.

Answered By: blast_hardcheese

I’m having the same dilemma as well. Did some search and found my answer(MHO):

Might as well quote from the documentation

Dynamic web applications need static files as well. That’s usually where the CSS and JavaScript files are coming from. Ideally your web server is configured to serve them for you, but during development Flask can do that as well. Just create a folder called static in your package or next to your module and it will be available at /static on the application.

IMHO: When your application is up for production, static file serving should be (or is ideally) configured on the webserver (nginx, apache); but during development, Flask made it available to serve static files. This is to help you develop rapidly – no need to setup webservers and such.

Hope it helps.

Answered By: jpanganiban

Another way to send static files is to use a catch-all rule like this:

@app.route('/<path:path>')
def catch_all(path):
    if not app.debug:
        flask.abort(404)
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    return f.read()

I use this to try to minimise the set-up when developing. I got the idea from http://flask.pocoo.org/snippets/57/

Further, I’m developing using flask on my standalone machine but deploying with Apache in production server. I use:

file_suffix_to_mimetype = {
    '.css': 'text/css',
    '.jpg': 'image/jpeg',
    '.html': 'text/html',
    '.ico': 'image/x-icon',
    '.png': 'image/png',
    '.js': 'application/javascript'
}
def static_file(path):
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    root, ext = os.path.splitext(path)
    if ext in file_suffix_to_mimetype:
        return flask.Response(f.read(), mimetype=file_suffix_to_mimetype[ext])
    return f.read()

[...]

if __name__ == '__main__':
    parser = optparse.OptionParser()
    parser.add_option('-d', '--debug', dest='debug', default=False,
                      help='turn on Flask debugging', action='store_true')

    options, args = parser.parse_args()

    if options.debug:
        app.debug = True
        # set up flask to serve static content
        app.add_url_rule('/<path:path>', 'static_file', static_file)
    app.run()
Answered By: Ben Golding

Even though this is an old answered question, I’m answering this because this post comes up pretty high in the Google results. While it’s not covered in the documentation, if you read the API docs for the Flask Application object constructor it’s covered. By passing the named parameter static_folder like so:

from flask import Flask
app = Flask(__name__,
            static_folder="/path/to/static",
            template_folder="/path/to/templates")

…you can define where static files are served from. Similarly, you can define a template_folder, the name of you static_url_path.

Answered By: Sean McSomething

The cleanest answer to this question is the answer to this (identical) question:

from flask import Flask, request, send_from_directory
app = Flask(__name__, static_folder='static')    

@app.route('/robots.txt')
@app.route('/sitemap.xml')
def static_from_root():
    return send_from_directory(app.static_folder, request.path[1:])

To summarize:

  • as David pointed out, with the right config it’s ok to serve a few static files through prod
  • looking for /robots.txt shouldn’t result in a redirect to /static/robots.txt. (In Seans answer it’s not immediately clear how that’s achieved.)
  • it’s not clean to add static files into the app root folder
  • finally, the proposed solution looks much cleaner than the adding middleware approach:
Answered By: bebbi

The best way is to set static_url_path to root url

from flask import Flask

app = Flask(__name__, static_folder='static', static_url_path='')
Answered By: dns

Try this:

@app.route("/ProtectedFolder/<path:filename>")
@CheckUserSecurityAccessConditions
def Protect_Content(filename):
  return send_from_directory((os.path.join(os.path.dirname(__file__), 'ProtectedFolder')),filename)
Answered By: Farzad Amirjavid