I'm creating a Flask app frontend, my index.html can't find the images and files referenced in the code.
I've tried moving to the same folder but with no success.
Server:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return open('html/index.html').read()
if __name__ == '__main__':
app.run(host='localhost', port=8000, debug=True)
HTML lines:
<img src="shards-logo-white.svg" alt="Example Navbar 1" class="mr-2" height="30">
<script src="js/shards.min.js"></script>
<script src="js/demo.min.js"></script>
Server debug output:
127.0.0.1 - - [30/Jan/2019 12:19:28] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [30/Jan/2019 12:19:29] "GET /shards-logo-white.svg HTTP/1.1" 404 -
127.0.0.1 - - [30/Jan/2019 12:19:29] "GET /html/js/shards.min.js HTTP/1.1" 404 -
127.0.0.1 - - [30/Jan/2019 12:19:29] "GET /html/js/demo.min.js HTTP/1.1" 404 -
The image shards-logo-white.svg is in the same folder.
The js scripts are with the subdirectory html -> js -> FILES.
No, Flask does not serve arbitrary files from the filesystem. Move any static files like those into the static subdirectory, then reference them via that path; you can use the full path of nested directoriess within the static path:
<img src="/static/shards-logo-white.svg" alt="Example Navbar 1" class="mr-2" height="30">
<script src="/static/html/js/shards.min.js"></script>
<script src="/static/html/js/demo.min.js"></script>
You could serve your HTML rendered from a template, at which point you can use {{ url_for('static', filename="shards-logo-white.svg") }} and {{ url_for('static', filename="html/js/shards.min.js") }}, etc. to have Flask generate valid URLs for those paths.
See the Static Files section of the quickstart, as well as the Static Files chapter of the tutorial.
If you are not using a template then may as well serve your html/index.html file as a static file too. As it stands you are not rendering it as a template nor are you making any other runtime changes to the file contents.
Even if you do sometimes need to conditionally serve a file from disk, rather than read it all into memory I'd use the flask.send_file() function to make sure the file is served efficiently and with a reasonable content-type header:
from flask import send_file
#app.route('/')
def hello():
return send_file('html/index.html')
Relative paths are resolved against Flask.root_path. You probably also want to consider flask.send_from_directory(), which will ensure that user-input for a filename can't be abused to serve arbitrary files outside of a designated directory.
Related
so I have tried paying some tutors to look at this and they cannot seem to find the issue. I have a really good feeling it is a directory issue.
Folder directory organization
App.py is outside all folders, inside a template folder is pricing.html, outside is another folder named css which has pricing.css.
I run my app.py which loads pricing.html to be able to press a button which goes to stripe checkout. The issue is, app.py finds the pricing folder, but the pricing.css does not load. Here is the html code in pricing.html:
<link rel="stylesheet" type="text/css" href="/css/style.css" media="screen">
Here is the app.py code:
from flask import Flask, redirect, request, render_template
import stripe
app = Flask(__name__,static_url_path="",static_folder="templates")
stripe.api_key = 'sk_test_51KzqK9Hj2B2Quz911XrP11cB4Jb2ESrDCelSpRIZBqa18TWO9bGKlyuWsmiNeGYEHw4224xx5ghUWDaTQOukRjcf00rHXcZGYU'
YOUR_DOMAIN = "http://localhost:5000"
#app.route('/create-checkout-session', methods=['POST'])
def create_checkout_session():
try:
checkout_session = stripe.checkout.Session.create(
line_items = [
{
'price': 'price_1KzrAtHj2B2Quz91wMDanJjz',
'quantity':1
}
],
mode="payment",
success_url=YOUR_DOMAIN + "/success.html",
cancel_url=YOUR_DOMAIN + "/cancel.html"
)
except Exception as e:
return str(e)
return redirect(checkout_session.url,code=303)
if __name__== "__main__":
app.run(port=5000,debug=True)
If I move the css folder inside the templates folder, the css will load, but I would have to change the html to all the other template and also I like this folder organization. Any thoughts?
Here is what is returned in terminal when I run it:
[20/May/2022 18:04:50] "GET /pricing.html HTTP/1.1" 200 -
[20/May/2022 18:04:51] "GET /css/style.css HTTP/1.1" 404 -
[20/May/2022 18:04:51] "GET /css/Pricing.css HTTP/1.1" 404 -
[20/May/2022 18:04:51] "GET /javascript/jquery.js HTTP/1.1" 404 -
[20/May/2022 18:04:51] "GET /javascript/nicepage.js HTTP/1.1" 404 -
[20/May/2022 18:04:51] "GET /css/images/GainesOpusInstitute4.png HTTP/1.1" 404 -
I believe that for flask to serve your css file it needs to be in the /static directory. Try moving your /css and /javascript folders into a directory at the same level called /static.
Then change your link to be:
<link rel="stylesheet" type="text/css" href="/static/css/style.css" media="screen">
See https://flask.palletsprojects.com/en/2.1.x/quickstart/#static-files for more info.
I'm studying flask, and got problems.
When I wrote code like this:
#app.route("/reference")
def reference():
return render_template("reference.html", css="reference", records=records)
The page http://127.0.0.1:5000/reference was working.
Then I found 'trailing slash' in flask document.
I wanted to apply it, so I edited code like this:
#app.route("/reference/")
def reference():
return render_template("reference.html", css="reference", records=records)
It was working too ! http://127.0.0.1:5000/reference/
But some problems were coming.
The browser couldn't read my css file (in html link.. href=blabla) with a changed log in python terminal.
GET /static/css/style.css HTTP/1.1 << before changing
GET /reference/static/css/style.css HTTP/1.1 << after changing
I redirected css file path,
href="static/css/style.css"
to
href="../static/css/style.css"
And It works.
I wanted to understand how 'trailing slash' do.
So I reset my code to first code.
Then 404 not found error raised and I got a not changed log.
"GET /reference HTTP/1.1" << log for first code
"GET /reference/ HTTP/1.1" << log for second code
"GET /reference/ HTTP/1.1" << log for reset code (== first code)
I got a question. What is happend?
I don't understand why it doesn't run like before.
I read https://flask.palletsprojects.com/en/2.0.x/quickstart/#unique-urls-redirection-behavior
But I still don't understand what is going on.
Why the GET path changed.. why the GET path doesn't changed.. why..
My mind is broken and I can't sleep.. please help me..
On top of what the unique-urls-redirection-behavior document says, when you use tags like <img src='some_url'> or <link href='some_url'> the behaviour may be different, as these URLs are loaded by the browser.
So with a route decorator like #app.route("/reference") which loads in the browser as example.com/reference a link tag with href="subpath/file.css" causes the browser to load that resource from example.com/subpath/file.css
On the other hand, with a route decorator like #app.route("/reference/") (with the trailing slash) which loads in the browser as example.com/reference/ (again, with the trailing slash) a link tag with href="subpath/file.css" causes the browser to load that resource from example.com/reference/subpath/file.css
This could explain the behaviour you are seeing.
To put this another way, consider this test app:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/a')
def a(): return render_template('index.html')
#app.route('/b/') # Note trailing slash
def b(): return render_template('index.html')
Paired with the following template at templates/index.html:
<html>
<head>
<link rel='stylesheet' href='subpath/file.css' />
</head>
Then make some hits and observe the asset requests in the console (they will give 404 errors because I haven't actually created the CSS files, this is just to show what the browser requests):
Load URL: http://localhost:5000/a:
"GET /a HTTP/1.1" 200 -
"GET /subpath/file.css HTTP/1.1" 404 -
Load URL: http://localhost:5000/b/:
"GET /b/ HTTP/1.1" 200 -
"GET /b/subpath/file.css HTTP/1.1" 404 -
Of course the correct way to include these assets is to use the url_for function.
So if I update the template to instead contain:
<link rel='stylesheet' href='{{ url_for("static", filename="file.css") }}' />
Then make the same request:
Load URL: http://localhost:5000/a:
"GET /a HTTP/1.1" 200 -
"GET /static/file.css HTTP/1.1" 404 -
Load URL: http://localhost:5000/b/:
"GET /b/ HTTP/1.1" 200 -
"GET /static/file.css HTTP/1.1" 404 -
As you can see here, the correct path for static assets will always be rendered, regardless of whether the endpoint has a trailing slash or not.
Let's say I've got this mcve:
mcve.py
import textwrap
from pathlib import Path
from flask import Flask
working_dir = Path(__file__).parent
app = Flask(
__name__,
# static_folder=str(working_dir / "uploads"),
)
#app.route("/test")
def index():
return textwrap.dedent(
"""
<!DOCTYPE html>
<html>
<head>
<title>Hello world</title>
</head>
<body>
<img src="foo/foo.png">
<img src="bar/bar.png">
</body>
</html>
"""
).strip()
if __name__ == "__main__":
with app.test_client() as c:
print(c.get("/test").data.decode("utf-8"))
run.bat
set FLASK_APP=mcve.py
set FLASK_ENV=development
flask run
If I execute run.bat and then I go to http://localhost:5000/test in the browser I'll get:
>flask run
* Serving Flask app "x.py" (lazy loading)
* Environment: development
* Debug mode: on
* Restarting with windowsapi reloader
* Debugger is active!
* Debugger PIN: 497-008-397
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [31/May/2020 22:32:19] "GET / HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /test HTTP/1.1" 200 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /foo/foo.png HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /bar/bar.png HTTP/1.1" 404 -
Question
How should I modify mcve.py to server the images properly (now you can see is giving 404) in development using flask's server but then serve them properly with nginx on production?
You don't have to configure flask specifically for this. These logs:
127.0.0.1 - - [31/May/2020 22:32:19] "GET / HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /test HTTP/1.1" 200 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /foo/foo.png HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /bar/bar.png HTTP/1.1" 404 -
are actually generated by the werkzeug development server that's serving the static content for you. When you move to using nginx, you can intercept the GET requests with a URL rule. From the example nginx config file from the Flask Mega Tutorial:
...
server {
...
location / {
# forward application requests to the gunicorn server
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static {
# handle static files directly, without forwarding to the application
alias /home/ubuntu/microblog/app/static;
expires 30d;
}
}
Note the /location rule that handles requests to static directly, so those requests from the browser wouldn't even hit whatever is serving your flask app in production. There are many more methods for matching urls that you can find, e.g. here. It's perfectly possible to add multiple such rules to look in separate locations but you'll want to structure the app to give these files a distinct location so you can implement such rules.
Separately, to get around your current 404s, look at the template docs for Jinja2 and use the url_for method to make sure it resolves relative paths correctly.
For example, if I want to include:
<link href='static/css/bootstrap-4.3.1.min.css' rel="stylesheet">
I would instead use:
<link href="{{ url_for('static', filename='css/bootstrap-4.3.1.min.css') }}" rel="stylesheet">
This passes off the responsibility of path resolution to the app, so no matter how many hyperlinks I've followed or blueprints I'm using, this path will always resolve to the correct static directory when the template is rendered.
I'm not sure this will work with return textwrap.dedent because it might not invoke Jinja on the template. You can import render_template_string for a throwaway example like you have here, but render_template will work in your actual app too.
This question already has answers here:
How to serve static files in Flask
(24 answers)
Closed 6 years ago.
I'm trying to use processing.js on my website but I keep getting the error: "processing.min.js Failed to load resource: the server responded with a status of 404 (NOT FOUND)"
I'm using Flask's render_template() to load in the test.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Processing.js</title>
<script src="processing.min.js"></script>
</head>
<body>
<h1>Processing.js</h1>
<script type="text/processing">
void setup() {
size(400,200);
textAlign(CENTER, CENTER);
background(0,0,100);
fill(255,230,75);
text("Processing.js", width/2, height/2);
noLoop();
}
void draw() {
}
void mouseMoved() {
stroke(255);
point(mouseX, mouseY);
redraw();
}
void mousePressed() {
line(0,mouseY,width,mouseY);
line(mouseX,0,mouseX,height);
println(mouseX, mouseY);
}
</script>
<canvas></canvas>
</body>
</html>
The flask file that I then run is simply:
from flask import Flask,request,render_template
app = Flask(__name__)
#app.route("/")
def hello():
return render_template('test.html')
if __name__ == '__main__':
app.debug = True
app.run()
When I run this on the local host: http://127.0.0.1:5000/ I see the header Processing.js but no actual canvas element.
According to Flask docs
Dynamic web applications also need static files. That’s usually where the CSS and JavaScript files are coming from. Ideally your web server is configured to serve them for you, but during development Flask can do that as well. Just create a folder called static in your package or next to your module and it will be available at /static on the application.
And as davidism commented, use the url_for template method to reference files
<script type="text/javascript" src="url_for('static', filename='processing.js')"></script>
Assuming that your static files (.js and .css) are in static folder.
I deployed a website (it consists of one index.html page and folders that contain js, image & css files) on the app-engine and linked it to my custom domain. I configured the CNAME and the site is opening on my domain, but the original appspot URL is not being redirected to the custom domain.
I did come across pages with similar questions which discussed about this problem. I tried implementing those, but they didn't seem to work.
Here is what I did, in the app.yaml file I replaced:
- url: /.*
static_files: static
upload: static
with
- url: /.*
script: main.application
and in the main.py, I erased all the content and added the following:
import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app
application = webapp2.WSGIApplication([
webapp2.Route('/', webapp2.RedirectHandler, defaults={'_uri':'http://subdomain.domain.com}),
], debug=False)
def main():
application.run()
if __name__ == '__main__':
main()
(Modified code after suggestions by Jeff)
But it doesn't seem to work. The appspot URL is not being redirected but my custom domain is working alright. What changes should I make in the above code to make the redirection possible?
Thanks!
Your application variable is not doing anything if that is the entire contents of your main.py file.
Add the following to bottom of main.py:
def main():
application.run()
if __name__ == '__main__':
main()
Also you probably don't need AllHandler since the route is redirecting everything.