58

Is that possible to add more static paths for my local dev Flask instance? I want to have default static folder for storing js/css/images files for the site and another folder, e.g. designs to keep my specific assets. I don't want to place designs folder inside static if there is a better solution exists.

Sergei Basharov
  • 51,276
  • 73
  • 200
  • 335

4 Answers4

59

I have been using following approach:

# Custom static data
@app.route('/cdn/<path:filename>')
def custom_static(filename):
    return send_from_directory(app.config['CUSTOM_STATIC_PATH'], filename)

The CUSTOM_STATIC_PATH variable is defined in my configuration.

And in templates:

{{ url_for('custom_static', filename='foo') }}

Caveat emptor - I'm not really sure whether it's secure ;)

plaes
  • 31,788
  • 11
  • 91
  • 89
  • 8
    In my eyes this is the most custom version but you should use `werkzeug.utils.secure_filename` to check the filename. – Jarus Mar 08 '12 at 17:00
  • clarification for anyone to come 'CUSTOM_STATIC_PATH' is I believe the actual folder name path. it's not some special key/variable.... which for some reason I thought it was. – Eiyrioü von Kauyf Oct 29 '12 at 23:24
  • 1
    actually, @Eiyrioü, I took it the other way, and also got it to work. I used the code as-is, and added a `CUSTOM_STATIC_PATH` variable in my config file. – domoarigato Nov 05 '14 at 17:03
  • 1
    what is `cdn` here? also should the `` be used as it is or should I replace `filename` with the actual file name? – Shantanu Shinde Jul 10 '19 at 11:13
  • 1
    @Jarus: `flask.send_from_directory` already checks that the filename don't point outside the directory. `werkzeug.utils.secure_filename` is for safely naming new files, and is not relevant here. I actually think it instead can break things by for example removing dirs, spaces and umlauts. – Mattias Wallin Oct 08 '21 at 05:52
51

You can use a Blueprint with its own static dir http://flask.pocoo.org/docs/blueprints/

Blueprint

blueprint = Blueprint('site', __name__, static_url_path='/static/site', static_folder='path/to/files')
app.register_blueprint(blueprint)

Template

{{ url_for('site.static', filename='filename') }}
famousgarkin
  • 13,687
  • 5
  • 58
  • 74
estin
  • 3,051
  • 1
  • 24
  • 31
  • 2
    This feels like the cleanest solution to me. It utilizes the existing mechanisms for serving static files and doesn't require adding routes for them. – bjg222 Jul 11 '23 at 17:44
3

If i have images stored in images dir like following

images/
  dir1/
    image1.jpg
  dir2/
    image2.jpg

then we can access these images with following url: http://localhost:5000/images/dir1/image1.jpg with the help of below code

from flask import Flask, send_from_directory


app = Flask(__name__, static_folder='main_static_dir')


@app.route('/images/<path:filename>')
def base_static(filename):
    return send_from_directory(app.root_path + '/images/', filename)


if __name__ == '__main__':
    app.run(debug=True)
Prasad
  • 1,028
  • 1
  • 11
  • 22
2

I wanted to expand on the accepted answer above for anyone who was wondering what app.config['CUSTOM_STATIC_PATH'] was being set to.

In my case I needed a /.well-known dir and so here's what I used:

I placed a new dir in my app root called well-known.
I set a config var like so:

CUSTOM_STATIC_PATH=app.root_path + '/well-known/'

I then used that var as such:

@app.route('/.well-known/<path:filename>')
def wellKnownRoute(filename):
    return send_from_directory(app.config['CUSTOM_STATIC_PATH'], filename, conditional=True)

Setting conditional=True is smart, this will 404 any requests where the file does not exist.

And of course if you're wondering why you need to set a config value for the dir path, you don't. You can always just use the config's value in place, giving you this instead:

@app.route('/.well-known/<path:filename>')
def wellKnownRoute(filename):
    return send_from_directory(app.root_path + '/well-known/', filename, conditional=True)

My files for the /.well-known URL path were always going to come from the app root /well-known dir so no point in making it more complicated.

And to note, you would be better off handling this particular case from nginx or whatever server you're using by setting up an additional server block and serving the file from outside the app, I just needed this setup for a dev env for testing.

Chase
  • 3,009
  • 3
  • 17
  • 23