I have a large website with hundreds of href=".html, href="css/, href="img/ and src="js/ references throughout the various html pages. I've placed all the css, js, img, sound, etc... folders in the "static" folder and all the html files in the "template folder".
I do not want to go through all my html files and manually edit each href using Flask's "url_for" function.
Is there a way that I can leave my existing html files alone and tell flask to use the css/, js/, and image paths defined in these html files?
Right now the following code leads to a bunch of 404 errors
import os
from flask import Flask, render_template
PROJECT_PATH = os.path.dirname(os.path.realpath(__file__))
app = Flask(__name__,
template_folder=os.path.join(PROJECT_PATH, 'templates'),
static_folder=os.path.join(PROJECT_PATH, 'static')
)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
Okay, based on Martijn's script, I got my site running using the following code. However, to catch my many href=someHTMLfile.html links in my index.html file, I added #app.route('/'). I'm wondering if there is a better way to do this?
from flask import Flask, render_template, safe_join, send_from_directory
app = Flask(__name__)
#app.route('/<any(css, js, img, fonts, sound):folder>/<path:filename>')
def toplevel_static(folder, filename):
filename = safe_join(folder, filename)
cache_timeout = app.get_send_file_max_age(filename)
return send_from_directory(app.static_folder, filename, cache_timeout=cache_timeout)
#app.route('/<path:filename>')
def public(filename):
return render_template(filename)
# #app.route('/')
# def index():
# return render_template('index.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
You can register additional routes to serve files from your static folder:
from flask import app, safe_join, send_from_directory
#app.route('/<any(css, img, js, sound):folder>/<path:filename>')
def toplevel_static(folder, filename):
filename = safe_join(folder, filename)
cache_timeout = app.get_send_file_max_age(filename)
return send_from_directory(app.static_folder, filename,
cache_timeout=cache_timeout)
#app.route('/<path:htmlfile>.html')
def toplevel_static(htmlfile):
filename = htmlfile + '.html'
cache_timeout = app.get_send_file_max_age(filename)
return send_from_directory(app.template_folder, filename,
cache_timeout=cache_timeout)
This replicates what the static view does, but for routes starting with /css/, /img/, /js/ or /sound/ instead. HTML files are loaded from your template folder instead.
Related
I have the following Flask app, and I am trying to load a js file from a template:
from flask import Flask, request, send_from_directory, render_template
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')
#app.route('/js/<path:path>')
def send_js(path):
return send_from_directory('js', path)
#app.route("/")
def main():
return render_template('index.html')
if __name__ == "__main__":
app.run()
Here is the folder:
My index.html file does load but the js doesn't:
<head>
<script src="/static/js/asynckittens.js"></script>
</head>
hello world
I have tried it as /js/asynckittens.js, and even /asynckittens.js and nothing will load this file. How can I load a js file in a basic flask server?
This question is possibly a duplicate of How to serve static files in Flask.
Flask is a great framework for developing web apps but its purpose is not to deploy(serve) web apps.
For that, you need a server(ngnix, apache etc)
For some reason, I had to delete the route serving js for flask to find these files:
#app.route('/js/<path:path>')
def send_js(path):
return send_from_directory('js', path)
I'm not sure why deleting that made it work but it did
I want to build a site. I have the index folder and the connected folder. Each folder also has a static folder. In the connected/static folder, I have the connected.css file, which I am trying to access, through my blueprint. However, the final page tries to access the connected.css from the index/static folder.
Where am I mistaking?
Useful code:
__init__.py:
from flask import Flask
from .index import index_routes
from .connected import connected_routes
def create_app():
app = Flask(__name__, template_folder="templates", static_folder="static")
app.register_blueprint(index_routes.index_bp)
app.register_blueprint(connected_routes.connected_bp, url_prefix='/connected')
return app
connected_routes.py
from flask import Blueprint
from flask import render_template
connected_bp = Blueprint('connected_bp', __name__, template_folder='templates', static_folder='static', url_prefix='/connected')
#connected_bp.route('/')
def connected():
return render_template('connected.html', title="Connected to Hattrick")
index_routes.py
from flask import Blueprint
from flask import render_template
index_bp = Blueprint('index_bp', __name__, template_folder='templates', static_folder='static')
#index_bp.route('/')
def home():
return render_template('index.html', title="The Best Match Predictor")
connected.html
<link href="{{url_for('static',filename='connected.css')}}" rel="stylesheet">
In the above line I have the problem.
Maybe give this a try:
<link href="{{url_for('connected.static',filename='connected.css')}}" rel="stylesheet">
For some elaboration: https://flask.palletsprojects.com/en/1.1.x/blueprints/#static-files
I am trying to return websites (html files) that are outside of the template directory.
Directory of the .py file:
archiv/archiv/web/article/articles.py
Directory of the html:
instance/articles/private/abc/abc.html
My articles.py code:
from flask import Blueprint, render_template
bp = Blueprint('articles', __name__, url_prefix='/articles')
#bp.route('/<article>')
def show_article(article):
"""Show a article."""
base_url = '/instance/articles/private/'
url_to_return = base_url + str(article) + '/' + str(article) + '.html'
# return render_template(url_to_return)
return "Hello " + article
The route gets accessed but once i am trying to return the website (comment) i does not work -> template not found. I am pretty sure that render_template isn´t the way to go but i haven´t found anything that could fit.
Could someone show me how to return the website abc.html once the route is called?
Thanks alot in advance
You could add a new template directory when creating the blueprint. When you pass a template name to the render_template function, it will also check the new location.
from flask import Flask, Blueprint, render_template
bp = Blueprint(
'articles',
__name__,
url_prefix='/articles',
template_folder="../instance", # New line!
)
#bp.route('/<article>')
def show_article(article):
"""Show a article."""
return render_template("articles/private/abc.html")
app = Flask(__name__)
app.register_blueprint(bp)
From Flask documentation (for a Blueprint)
template_folder – A folder with templates that should be added to the app’s template search path. The path is relative to the blueprint’s root path. Blueprint templates are disabled by default. Blueprint templates have a lower precedence than those in the app’s templates folder.
If you want to add that template directory to the whole app, you can set template_name when creating Flask instance. Check this for more.
I have a Flask back-end with API routes which are accessed by a React single page application created using create-react-app. When using the create-react-app dev server, my Flask back end works.
I would like to serve the built (using npm run build) static React app from my Flask server. Building the React app leads to the following directory structure:
- build
- static
- css
- style.[crypto].css
- style.[crypto].css.map
- js
- main.[crypto].js
- main.[crypto].js.map
- index.html
- service-worker.js
- [more meta files]
By [crypto], I mean the randomly generated strings generated at build time.
Having received the index.html file, the browser then makes the following requests:
- GET /static/css/main.[crypto].css
- GET /static/css/main.[crypto].css
- GET /service-worker.js
How should I serve these files? I came up with this:
from flask import Blueprint, send_from_directory
static = Blueprint('static', __name__)
#static.route('/')
def serve_static_index():
return send_from_directory('../client/build/', 'index.html')
#static.route('/static/<path:path>') # serve whatever the client requested in the static folder
def serve_static(path):
return send_from_directory('../client/build/static/', path)
#static.route('/service-worker.js')
def serve_worker():
return send_from_directory('../client/build/', 'service-worker.js')
This way, the static assets are successfully served.
On the other hand, I could incorporate this with the built-in Flask static utilities. But I do not understand how to configure this.
Is my solution robust enough? Is there a way to use built-in Flask features to serve these assets? Is there a better way to use create-react-app?
import os
from flask import Flask, send_from_directory
app = Flask(__name__, static_folder='react_app/build')
# Serve React App
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def serve(path):
if path != "" and os.path.exists(app.static_folder + '/' + path):
return send_from_directory(app.static_folder, path)
else:
return send_from_directory(app.static_folder, 'index.html')
if __name__ == '__main__':
app.run(use_reloader=True, port=5000, threaded=True)
Thats what I ended up with. So bascially catch all routes, test if the path is a file => send file => else send the index.html. That way you can reload the react app from any route you wish and it does not break.
First do npm run build to build the static production files as mentioned by you above
from flask import Flask, render_template
app = Flask(__name__, static_folder="build/static", template_folder="build")
#app.route("/")
def hello():
return render_template('index.html')
print('Starting Flask!')
app.debug=True
app.run(host='0.0.0.0')
Unfortunately, I don't think you can get it work with the development hot-reload.
A working solution here.
Ever thought why we need two separate folders for static and templates. To segregate the mess, right?
But, it's a problem with the production build since it has one folder for both static and templates type of files and all dependencies are linked like that.
The build folder will be served if you consider it both static and templates.
Use something like this
from flask import Flask, render_template
app = Flask(__name__, static_url_path='',
static_folder='build',
template_folder='build')
#app.route("/")
def hello():
return render_template("index.html")
Your flask app will run fine.
The accepted answer does not work for me. I have used
import os
from flask import Flask, send_from_directory, jsonify, render_template, request
from server.landing import landing as landing_bp
from server.api import api as api_bp
app = Flask(__name__, static_folder="../client/build")
app.register_blueprint(landing_bp, url_prefix="/landing")
app.register_blueprint(api_bp, url_prefix="/api/v1")
#app.route("/")
def serve():
"""serves React App"""
return send_from_directory(app.static_folder, "index.html")
#app.route("/<path:path>")
def static_proxy(path):
"""static folder serve"""
file_name = path.split("/")[-1]
dir_name = os.path.join(app.static_folder, "/".join(path.split("/")[:-1]))
return send_from_directory(dir_name, file_name)
#app.errorhandler(404)
def handle_404(e):
if request.path.startswith("/api/"):
return jsonify(message="Resource not found"), 404
return send_from_directory(app.static_folder, "index.html")
#app.errorhandler(405)
def handle_405(e):
if request.path.startswith("/api/"):
return jsonify(message="Mehtod not allowed"), 405
return e
I used a flask server with only one route / which read the index.html file from the build folder of Create react app(CRA)
from flask import Flask
app = Flask(__name__)
app.static_folder = '../build'
#app.route('/')
def index():
fref = open(r'../build/index.html')
html_text = fref.read()
fref.close()
return html_text
app.run()
Setting up this way I faced an error, the static files are not properly served due to path mismatch, so the solution I used is
Add a homepage property in package.json of CRA and set it to "/static"
{
"name":"App-name",
"version":"",
"dependencies":{}
"homepage":"/static",....[other keys]}
Add **homepage** key parallel to the **dependencies** key in the package.json file
This homepage property will be used during the build process of CRA and used in the place of %PUBLIC_URL% of index.html and gets appended to other static assets URL path (you can verify by viewing the index.html code after the build process)
After the build process, run the flask server,we can see the GET request coming with / for the first time and index.html will be served and followed by requests /static/static/js/[[filename]] for other static assets from HTML file and everything works correctly
I'm trying to add an image to my quiz.html page with Flask using:
<img src='{{url_for('static', filename='img/question-mark.png')}}' alt='' >
When I look at the page source, it's interpreted as:
http://127.0.0.1:5000/quiz/static/img/question-mark.png rather than:
http://127.0.0.1:5000/static/img/question-mark.png
Yet, my .css files and .js files load in quiz.html using the same syntax just fine. How can I get the correct static file path?
My current structure is:
|-app.py
|-templates/
|-main.html
|-quiz.html
|-static/
|-css/
|-img/
app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def homepage():
return render_template("main.html")
#app.route('/quiz/')
def quiz():
return render_template("quiz.html")
if __name__=="__main__":
app.run(debug=True)
You don't need a Jinja script to write a static image source. Just write:
<img src="/static/img/question-mark.png">
All the static resources are automatically served under /static.