32

I have a html file which references static object like this

<img src="img/snacks.png">
<link href="css/bluestrap.css" rel="stylesheet">

Hence the browser tries to call this via and flask fails to do so

http://127.0.0.1:5000/img/snacks.png  

There are lots of such references across multiple files hence changing the references is not possible. How do i serve these static files from FLASK

I have copied all these static files to the 'static' folder and tried this

@app.route('/<path:filename>')  
def send_file(filename):  
      return send_from_directory('/static', filename)

However this does not work, Is there any other way to do this ? or what am i doing wrong ?

Rijul Jain
  • 361
  • 1
  • 3
  • 4
  • Does this answer your question? [How to serve static files in Flask](https://stackoverflow.com/questions/20646822/how-to-serve-static-files-in-flask) – ggorlen May 01 '23 at 18:06

7 Answers7

33

In production, you don't want to serve static files using the flask server. I suggest you use a proper web server to do that.

For dev, since you don't want to use url_for, you can try to initialize your flask app as below. This way, flask knows where your static files are.

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

@app.route('/<path:filename>')  
def send_file(filename):  
    return send_from_directory(app.static_folder, filename)

See this post with a lot of info Static files in Flask - robot.txt, sitemap.xml (mod_wsgi)

Community
  • 1
  • 1
codegeek
  • 32,236
  • 12
  • 63
  • 63
  • There are too many references of images / css files to change them using url_for function , that is why i don't want to change them . Is there no way to not change the html file and still serve them from python ? – Rijul Jain Jul 16 '13 at 16:25
  • with "main" blueprint can not use it – Beqa Bukhradze Jul 10 '18 at 13:36
  • Flask `url_for` with `'static'` already calls `send_from_directory`, I don't see your point – Mojimi Jun 28 '19 at 12:26
  • One caveat for me was to make sure that `filename` is really just a filename and not a path to a file in a subdir. The static folder can also be specified manually, but it needs to be the absolute path. Use `os.path.realpath()` to get it. – stefanbschneider Aug 22 '19 at 09:19
14

If you look at the docs for send_from_directory you'll see that it takes the path to the directory in which the files are held on disk. Unless you have your image files saved in a root-level directory named static, you'll want to update your file path:

send_from_directory("/some/path/to/static", "my_image_file.jpg")

That being said, if you are using this for anything that will be under any load, it is better to ensure that your web server serves the files, rather than serving static files from your application.

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • My files are stored in a folder called 'img' inside a root level directory called 'static', so effectively its stored at static/img/snacks.png and browser calls http://127.0.0.1:5000/img/snacks.png – Rijul Jain Jul 16 '13 at 16:56
  • @RijulJain - yes, but is that directory located at `/static` on disk? That is, is it next to `usr`, `etc` and so on under `/` in your *file system* (not your webserver root)? – Sean Vieira Jul 16 '13 at 16:59
  • That is in my webserver root , how do i give path relative to my webserver root ? – Rijul Jain Jul 16 '13 at 17:22
  • NOT a single answer from top to bottom can be used ! – Thư Sinh Sep 11 '21 at 23:06
7

Don't use Flask's built-in server in production. It is for development only! And don't use Flask to serve static assets. It's slow! In production use a webserver in front of Flask like apache2, nginx or lighttpd. These servers are able to rewrite a URL and serve static assets.

How to deploy Flask: http://flask.pocoo.org/docs/deploying/

How to rewrite a URL: apache2, nginx, lighttpd.

dAnjou
  • 3,823
  • 7
  • 27
  • 34
3

I think a better way to do this would be:

import flask

# ...

@app.route('/img/<fname>')
def legacy_images(fname):
    return flask.redirect(flask.url_for('static', filename='img/' + fname), code=301)

Instead of sending the files on two different locations, this would do a permanent redirect to the proper URL. As others have said, it's also a good idea to serve static files directly with nginx or Apache.

Markus Unterwaditzer
  • 7,992
  • 32
  • 60
2

You should remove "/" before "/static" in your code:

send_from_directory('/static', filename)

change it to:

send_from_directory('static', filename)

However, in some environments, the server itself does not let running this command on the static folder/directory. Because it is set to be a static file server. For example, with the google cloud, you should build a directory called tmp beside the static folder and then do the send_from_directory command with the tmp folder:

return(send_from_directory('tmp', filename))
Farzad Amirjavid
  • 649
  • 5
  • 13
0

Use:

@app.route('/<path:filename>')  
def send_file(filename):
      from pathlib import Path
      root = Path('.')
      folder_path = root / 'static'
      return send_from_directory(folder_path, filename, as_attachment=True)
VirtualScooter
  • 1,792
  • 3
  • 18
  • 28
  • 1
    While this code might answer the OP's question, you could make your answer much better by appending an explanation on how your code solves the problem – Simas Joneliunas Jul 06 '21 at 00:08
0

This answer is for Flask Version 2.3 this is reference for documentation https://flask.palletsprojects.com/en/latest/api/#flask.send_from_directory this an example

@app.route('/download:')
def download():
    return send_from_directory(directory='static/files', path="cheat_sheet.pdf", as_attachment=False)

app hierarchy