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.
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.
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:
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">
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).
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)
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
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.
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.
app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location
So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)
By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.
One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html
The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.
If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images
This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.
For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
Related
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.
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.
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:
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">
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).
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)
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
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.
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.
app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location
So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)
By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.
One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html
The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.
If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images
This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.
For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
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.
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.
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:
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">
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).
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)
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
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.
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.
app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location
So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)
By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.
One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html
The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.
If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images
This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.
For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
I'm new to Python and Flask.
Implementing using Flask framework.
Folder: F1->app.py,F2->a.md,b.md
When i run app.py , it displays link.html result(web page displays 2 links). When I click on the 1st link(F2/a.md), it should parse a.md file and render the result in html format. When I click on the second link(F2/b.md), it should parse b.md file and render the result in html format.
app.py :
from flask import Flask,render_template
app=Flask(__name__)
#app.route('/')
def index():
return render_template('link.html')
#app.route('/Link')
def display():
#code to recursively read and parse the file->struck here
return render.template("page.html")
if __name__=="__main__":
app.run(debug=True)
link.html
<html>
<body>
<ul >
<li>F2/a.md</li>
<li>F2/b.md</li>
</ul>
</body>
</html>
page.html
<html>
<body>
{{ text|markdown }}
</body>
</html>
Please help me.
There's an arugment for rendering the markdown on the client side with Javascript, but for a basic example, this could be done on the server side with help of the Python library mistune:
pip install mistune
Let's have our app list the contents of the directory on startup. Here we'll assume the markdown files are in the subdirectory files/:
from flask import Flask, abort, render_template
import os
import mistune
MD_DIR = 'files' # Dir containing .md files
md_files = [] # empty list to add .md files to
for file in os.listdir(MD_DIR):
if file.endswith('.md'):
md_files.append(file)
app = Flask(__name__)
md_files is now a list which contains all the files with a .md extension in the files/ directory.
Now add a route which will do the listing. We pass md_files to the template:
#app.route('/')
def index():
return render_template('link.html', md_files = md_files)
And a corresponding template to handle this at templates/link.html:
<html>
<head>
<title>File List</title>
</head>
<body>
<ul>
{% for file in md_files %}
<li>
<a href='{{ url_for("render", file=file) }}'>{{ file }}</a>
</li>
{% endfor %}
</ul>
</body>
</html>
Notice this uses the url_for function to build the list dynamically, based on what's in the md_files list. Next we need to create our render function which takes an argument file:
#app.route('/render/<file>')
def render(file):
if file not in md_files:
abort(404)
else:
path = os.path.join(MD_DIR, file)
with open(path) as f:
data = f.read()
return render_template('render.html', data=mistune.markdown(data))
This first checks that whatever was provided as file in the URL string is in fact in that md_files list, otherwise throws a 404.
If valid it reads the data and renders another template, setting the data variable to the return value of mistune.markdown() which gives us the HTML based on that markdown.
The template for this at templates/render.html should look like this:
<html>
<body>
{{ data | safe }}
</body>
</html>
Notice we're using the safe filter, as we don't want the HTML provided in this variable to be escaped.
This is because what mistune does is returns HTML based on provided markdown. This is best demonstrated at the terminal:
>>> import mistune
>>> mistune.markdown('# I am a header')
'<h1>I am a header</h1>\n'
>>>
The directory structure at this stage looks like:
.
├── app.py
├── files
│ ├── 1.md
│ └── 2.md
└── templates
├── link.html
└── render.html
Some possible disadvantages with this approach:
You need to restart the app to have it re-read what's in the files/ subdirectory. If that directory is going to be updated while the server is running, you could move the directory listing code into the index function, so the directory contents are listed on each request. If the contents of the directory don't change this is probably in-efficient.
EDIT as per comment:
If you wish to recursively look for .md files in the MD_DIR folder you could use glob:
import glob
Then replace the for loop which builds md_files with:
for file in glob.glob(os.path.join (MD_DIR, "**/*.md"), recursive = True):
if file.endswith('.md'):
md_files.append(file)
This means items in md_files don't begin with ./ (which is the case in your os.walk modification), instead they look more like:
['files/1.md', 'files/2.md', 'files/subdir/deeptest.md']
This should be rendered in the links correctly, and of course in the render function, always ensure to:
if file not in md_files:
abort(404)
This ensures nothing is served if it's not in that md_files list.
I have done few modification to my code.
from flask import Flask, abort, render_template
import os
import mistune
app=Flask(__name__)
md_files = []
for subdir, dirs,files in os.walk('./'):
for file in files:
if(file.endswith('.md')):
md_files.append(os.path.join(subdir,file))
#app.route('/')
def index():
#link.html page produces the links [./Folder1/a.md,./Folder1/b.md, ./Folder2/a.md] as per my requirement.
return render_template('link.html', md_files = md_files)
#app.route('/render/<file>')
def render(file):
if file not in md_files:
abort(404)
else:
#When i click on the link, it doesn't display the html page
#I'm getting error(requested URL was not found on the server)
#I think it's because file holds value like ./Folder1/a.md
#I don't understand how to read that!
with open(file) as f:
data = f.read()
return render_template('render.html', data=mistune.markdown(data))
if __name__=="__main__":
app.run(debug=True)
Please help me to solve this!
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.
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.
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:
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">
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).
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)
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
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.
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.
app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location
So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)
By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.
One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html
The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.
If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images
This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.
For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
I am trying to display an HTML file from my Django code. but my file is getting downloaded instead of displaying.
Following is my code:
#api_view(['GET'])
def download_y9cfile1(request, file_name):
filePath = CommonUtils.get_absolute_file_path('app', 'static', 'generated', 'HTML' , file_name)
return render(request, file_name)
render()
render is supposed to work with a django template name, not the complete file input. So, you could try placing the generated file in the template path (do not add the static directory to the template paths, though!) and use the template's relative path as argument.
Regular HttpResponse
Or you load the HTML content as file stream and return it in a regular response with content type set to text/html.
Staticfiles
Of course, you could also use the the staticfiles module to simply serve that html file the same way it serves JS and CSS files. The path from which you load the file suggests that you actually simply want to serve a static resource. That would be the Django way.
More on staticfiles (reading the documentation also helps):
If this is in <project_dir>/<app_dir>/settings/base.py:
APP_DIR = os.path.dirname(os.path.realpath(project_module.__file__))
PROJECT_ROOT = os.path.dirname(APP_DIR)
STATIC_URL = '/static/'
STATICFILES_DIRS = (
# this would contain your "generated" directory
# you can link several directories here if you'd rather
# have "generated" as a root directory (url wise)
os.path.join(APP_DIR, 'static'),
)
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static_collected')
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'compressor.finders.CompressorFinder',
)
In your top most urls.py:
urlpatterns = [
...
] + static.static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG:
urlpatterns += [
url(r'^static/(?P<path>.*)$', never_cache(serve_static)),
# url(r'^__debug__/', include(debug_toolbar.urls)),
]
On production, static_collected would best be served by Nginx or Apache Http. If you need special URLs for your generated files, however, you might really need an explicit view for those, and a URL pattern definition.
CSS Resources / Template Solution
Example for your Django templates that would automatically create the correct URLs:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'lib/css/jquery-ui.min.css' %}"/>
You might want to reconsider changing your generated htmls to Django templates in order to avoid including hard coded static URLs inside. For example, you could generate only the vital part and then include it as context variable when rendering the response using a super template:
views.py
class GeneratedFileView(TemplateView):
template_name = 'templates/super_generated_view.html'
def get_context_data(self, **kwargs):
gc = ... # get the generated content here, as string
return super().get_context_data(generated_content=gc, **kwargs)
Everything else is TemplateView magic.
templates/super_generated_view.html
<!doctype html>
{% load static compress %}
<html lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="UTF-8"/>
..... css and js etc. directives
</head>
<body>
{{ generated_content }}
</body>
This is just a quick example. If you need CSS/JS depending on the generated content, you might need a more refined logic.