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')
[ Environment: symfony (PHP), twig files with HTML/JS code, and Managing assets with Webpack ]
Files Tree
_assets
|__js
|__file.js
|__library
|__ps
|__index.js
_public
|__build
|__js
|__myfile.js (auto generated by webpack)
_src
_templates
|__mypage
|__page.html.twig
_webpack.config.js
Normally in a file.js you perform an import, and then use/call the exported functions/variables using the alias given:
library/ps/index.js
export function x(){
console.log('hi !');
}
file.js
import * as myalias from "../../../assets/js/library/ps";
myalias.x();
webpack.config.js
...
.addEntry('js/myfile', './assets/js/file.js')
...
page.html.twig
...
{% block javascript %}
{{ encore_entry_script_tags('js/myfile') }}
{% endblock %}
...
web console (google chrome)
hi !
(EVERYTHING UTIL HERE WORKS PERFECTLY)
Files Tree
_assets
|__js
|__library
|__ps
|__index.js
_public
|__build
|__js
|__mylibrary.js (auto generated by webpack)
_src
_templates
|__mypage
|__page.html.twig
|__page_JS.html.twig
_webpack.config.js
My Goal is to do the same thing, but having the JS code in a twig file. Because I gain more advantages passing, in some cases, the twig variables to the js code.
The problem is that I get an error, in the web console. Uncaught TypeError: myalias.x is not a function
library/ps/index.js
export function x(){
console.log('hi !');
}
webpack.config.js
...
.addEntry('js/mylibrary', './assets/js/library/ps/index.js')
...
page_JS.html.twig
<script type="module">
import * as myalias from "{{ asset('build/js/mylibrary.js') }}";
myalias.x();
</script>
the code is inside the <scrip type="module">, because with it, we can use the import/export functionalities that normally inside a normal <script> we don't have. (if I understood right)
PS. the path is build because the webpack generate the file in the public folder.
page.html.twig
...
{% block javascript %}
{% include 'mypage/_page_JS.html.twig' %}
{% endblock %}
...
web console (google chrome)
Uncaught TypeError: myalias.x is not a function
I'm trying to implement Ajax functionality into my website. This seems to be a moderately common problem, but all solutions to it I've found online have been simple, like forgetting something in the tutorial. The error message appears in the JavaScript console.
I'm trying to follow this tutorial: http://django-dajaxice.readthedocs.org/en/latest/installation.html
My actions:
I used pip install django_dajaxice for install
I copy-pasted the settings.py and urls.py code in the tutorial into my own:
from dajaxice.core import dajaxice_autodiscover, dajaxice_config
dajaxice_autodiscover()
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns = patterns('',
# AJAX
url(dajaxice_config.dajaxice_url, include('dajaxice.urls')),
)
urlpatterns += staticfiles_urlpatterns()
and
STATICFILES_FINDERS = ( ... ) # Exact copy paste from tutorial
TEMPLATE_LOADERS = ( ... ) # Exact copy paste from tutorial
TEMPLATE_CONTEXT_PROCESSORS = ( ... ) # Exact copy paste from tutorial
I included the template tags in my base.html, the actual html file inherits from that
Then Quickstart: http://django-dajaxice.readthedocs.org/en/latest/quickstart.html
I created content/ajax.py (content is my app). Code inside is simple:
from dajax.core import Dajax
from content import models
from dajaxice.decorators import dajaxice_register
#dajaxice_register
def fav(request):
dajax = Dajax()
return dajax.json()
Finally, the JS and HTML code which instantiates the AJAX:
<script type="text/javascript" src="{{ STATIC_URL }}dajaxice/dajaxice.core.js"></script>
function js_callback(data) {
Dajax.process(data);
alert(data.message);
}
<a onClick="Dajaxice.content.fav(js_callback);">Favorite</a>
You need to run collectstatic again to regenerate dajaxice.core.js.
And maybe you should remove the static files has been collected before.
I am trying to send the path for my javascript folder to a template using Jinja2. The javascript folder is in the same path as the index.py, but the problem is that index.html is in the templates folder and cannot load the url. So how can I send a relative url with jinja?
index.py
import cherrypy
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
class Root:
#cherrypy.expose
def index(self):
tmpl = env.get_template('index.html')
sidebar = env.get_template('sidebar.html')
return tmpl.render(javascript_folder="js",sidebar=sidebar.render())
templates/index.html
<script src="{{javascript_folder}}+/jquery.js" >
If your js path won't change then I would just use a static path.
<script src="/js/jquery.js" >
If you want to physical path to the js file to change depending on what system you're on here's how you could do that...
import os
import cherrypy
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
class Root:
#cherrypy.expose
def index(self):
tmpl = env.get_template('index.html')
return tmpl.render(javascript_folder=os.path.dirname(__file__),sidebar=sidebar.render())
But Daniel is correct that you'll need to enable static content serving in cherrypy. Here's how to do that...
config = {'/static':
{'tools.staticdir.on': True,
'tools.staticdir.dir': PATH_TO_STATIC_FILES,
}
}
cherrypy.tree.mount(MyApp(), '/', config=config)
http://docs.cherrypy.org/stable/progguide/files/static.html
Hope this helps!