I am trying to display the image on my local machine. I only use the website from my own machine. I am not expecting visit from outside. I found a solution here: Get Flask to show image not located in the static directory, But it doesn't work for me. I have tried:
relative path, abs path. None of them works. Where I did it wrong?
QUESTION:
for test purpose, my file system is like this:
C:/jackson/Python34_workspace/Python34_Projects/Learn-Bottle/app05_rend_local_img/
picuture_gallery/Desert.jpg
views/index.tpl
main.py
python script is this
#bottle.route("/")
def index():
return bottle.template("index.tpl")
#bottle.post('/result')
def result():
return bottle.template("index.tpl")
And this is my template.
<form action="/result" method="POST">
<br>
<input type="submit" value="Submit">
<br>
</form>
<div>
<img src="file:///C:/HSH/Python34_workspace/Python34_Projects/Learn-Bottle/app05_rend_local_img/picture_gallery/Desert.jpg">
</div>
--- Some comment ---
I have tried
src="file:///picuture_gallery/Desert.jpg"
after I clicked submit, it doesn't display. But if I drag it to the browser, it works. How could that be?
An URL using the file procotol is never requested from the server. The client (browser) always looks for it on the local system.
So it doesn't matter how you configure your Bottle application, the browser will not ask it for such an URL.
If you want the Botte application to deliver static files, do something like this:
from bottle import static_file
#route('/static/<filename>')
def server_static(filename):
return static_file(filename, root='/path/to/your/static/files')
Related
I am old timer but young learner. I want make my own website, using Python and Bottle.
I have an HTML page which contains a title, a subtitle and a photo. This is a template used by Bottle in this little code:
from bottle import route, run, view
#route("/")
#view("pagedegarde.html")
def menu() :
contenu = "Moto de l'abbé Khan"
return {"titre" : "Bécanes", "contenu" : contenu}
run(host = '0.0.0.0', port = 8080, debug = True, reloader = True)
Here is the template, "gardepage.html":
<!doctype html>
<!-- page_de_garde.tpl -->
<HTML lang="fr">
<HEAD>
<TITLE>{{titre}}</TITLE>
<meta charset="UTF-8">
</HEAD>
<body>
<header>
<h1>Phrases et attrapes</h1>
</header>
<h3>{{titre}}</h3>
<p><image src="turquoise.jpg" alt="125 k4" /></p>
{{!contenu}}
<hr/>
</body>
</html>
The photo is in the same directory as the template and the python file.
Results :
127.0.0.1 - - [13/Mar/2022 11:10:58] "GET /turquoise.jpg HTTP/1.1" 404 746
The page is displayed, the title, the subtitle, but not the photo, there is instead the alternative mention "125 k4".
I wonder what it is, "746". Since I've had so many 404s (!), I've found that terminal messages always follow "404" with another number. I tried to find out about it, but couldn't find anything.
Otherwise, if I click on the html file, it displays without a problem, including the photo.
I tried both suffixes .tpl or .html, there is no difference. I tried .png or .jpg : no difference.
And I get the same result with Python 3.8.1 and Bottle 0.12.7 or with Python 3.10.2 and Bottle 0.12.19.
Thanks for reading me.
Bottle doesn't serve image/js/css automatically - you have to add own function for this.
It is simpler if you put static files in subfolder because then function can recognize this folder in url and run correct function. And this is popular method in other frameworks.
See: Routing Static Files
Example uses subfolder static for this - so you should have files
main.py
pagedegarde.html
static/turquoise.jpg
from bottle import route, run, view, static_file
#route("/")
#view("pagedegarde.html")
def menu() :
contenu = "Moto de l'abbé Khan"
return {"titre" : "Bécanes", "contenu" : contenu}
#route('/static/<filepath:path>')
def server_static(filepath):
return static_file(filepath, root='static/')
# or with full path
#return static_file(filepath, root='/full/path/to/static/')
run(host='0.0.0.0', port=8080, debug=True, reloader=True)
And remember to use /static in HTML
<p><image src="/static/turquoise.jpg" alt="125 k4" /></p>
Other frameworks may have the same problem. Some may serve static file only in debug mode but in normal mode they should be executed with web servers like Apache or nginx which should serve static files (because they do this faster)
EDIT:
To serve image in the same folder you would need to use regex to recognize filename in URL
#route('<filepath:re:.*\.(jpg|png|gif)>')
def server_static(filepath):
return static_file(filepath, root='')
The same you would have to do for other static files .css, .js, etc.
And if you would like to server other files for downloading or displaying then you would have to add also other extensions - ie. .csv, .xls, .mov, .mp3, etc.
If you would use regex .* as last route then it would serve all files (which don't match to previous routes)
#route('<filepath:re:.*>')
def server_static(filepath):
return static_file(filepath, root='')
but it is not safe because someone could run ie. http://0.0.0.0:8080/main.py to download source code.
I am having a problem with audio playback at the front. This problem is only present when deploying to prod. When launched locally, audio is played. When I launch it on production, when I play audio (via the a tag), I get the following message: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME.
Can you please tell me which way to look, where to look for a solution? I've already googled everything and zero information. I would be extremely grateful. Thank you.
Backend on Flask:
import os
from flask import Flask, Response, request
from flask_cors import CORS
app = Flask(name)
CORS(app)
def generate_wav(path: str, count_read=65536):
with open(path, "rb") as fio:
data = fio.read(count_read)
while data:
yield data
data = fio.read(count_read)
#app.route("/get-wav")
def get_wav():
path = request.args.get('path')
return Response(generate_wav(path), mimetype="audio/x-wav")
Frontend, working version (local):
<audio controls>
<source src="localhost:5000/get-wav?path=/full_path/file.wav" type="audio/wave">
<p>
Your browser does not support HTML5 <code>audio</code>.
To listen, click on link
</p>
</audio>
Frontend, non-working version on prod (another computer):
<audio controls>
<source src="external_address.com/get-wav?path=/full_path/file.wav" type="audio/wav">
<p>
Your browser does not support HTML5 <code>audio</code>.
To listen, click on link
</p>
</audio>
#Danil, the below are some of the options which you can try:
One:
According to net-informations the error Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME is caused when the default http or https are not the types to . They suggest adding target="_blank" to avoid the issue. I personally feel it could be also the way the api itself is designed. For that, please look to option three.
Two:
Using jinja template instead of html. You can change the plain html into jinja to see if that functions as expected.
From:
#app.route("/get-wav")
def get_wav():
path = request.args.get('path')
return Response(generate_wav(path), mimetype="audio/x-wav")
<audio controls>
<source src="localhost:5000/get-wav?path=/full_path/file.wav" type="audio/wave">
<p>
Your browser does not support HTML5 <code>audio</code>.
To listen, click on link
</p>
</audio>
To:
#app.route("/get-wav/<string:name>")
def get_wav():
path = os.path.join("your/absolute/base_dir", name)
return Response(generate_wav(path), mimetype="audio/x-wav")
<audio controls>
<source src="{{ url_for("get_wav", name=file.wav) }}" type="audio/wav">
<p>
Your browser does not support HTML5 <code>audio</code>.
To listen, click on link
</p>
</audio>
Three:
Your current api is designed as follows, https://api.domain.com/get-wav?path=/full_path/file.wav. This design would make the path vulnerable and exposed to be retrieved. Hence, I would propose you try the uploads folder option provided from flask and implement it accordingly.
A simple example based on flask documentation:
You will first need to set the uploads folder
import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/path/to/the/uploads' # This is the top level folder name of your wav files
ALLOWED_EXTENSIONS = {'wav', 'mp3'} # Supported extensions
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
Now, when you want to get a wav file, then do the following:
from flask import send_from_directory
#app.route('/uploads/<name>')
def get_wav(name):
# Here, you can use the name to perform some operations, such as generate_wav. But, if you are not generating the wav you could also return an already generated one here using send_from_directory.
return send_from_directory(app.config["UPLOAD_FOLDER"], name)
Finally, you will have to use jinja to source the api as file and obtain it as follows:
<audio controls>
<source src="{{ url_for("get_wav", name=file.wav) }}" type="audio/wav">
<p>
Your browser does not support HTML5 <code>audio</code>.
To listen, click on link
</p>
</audio>
Some References:
Handling File uploads
Flask file uploads
jinja2
This question already has answers here:
How to serve static files in Flask
(24 answers)
Link to Flask static files with url_for
(2 answers)
Closed 2 years ago.
working on a small project, for which I have an HTML page. For now it is a static page, with everything hard-coded.
When I preview it locally, it appears fine. But when the same page is returned from flask using render_template, the image link appears broken.
Following is the structure of directory:
/
-server.py
--templates/
---org_dashboard.html
---img_avatar.png
Im attaching screenshots as well as code snippets from return function, and the corresponding HTML code.
Python/flask code:
#app.route('/org_dashboard', methods=['GET', 'POST'])
def org_dashboard():
return render_template('org_dashboard.html')
Corresponding HTML code with image path:
<div class="card-columns">
<div class="card">
<img src="img_avatar.png" alt="Avatar" style="width:100%">
<div class="container">
<h4><b>John Doe</b></h4>
<p>Architect & Engineer</p>
</div>
</div>
</div>
When returned from localhost by flask. Notice the link appears broken:
Click here to view image
When viewed directly by opening the HTML file. Image appears fine Click here to view screenshot
The problem is that your image path is implying something that is only true in a static local HTML file.
src="img_avatar.png" tells the browser that the file is located in the same folder as the current page.
You need to change this to a relative path like this: src="/static/img_avatar.png" and then move the file to the /static folder in your project root.
Flask makes the assumption that you will do this and automatically adds a static view that takes a path relative to the project_root/static directory and serves it.
A .tar.bz2 file served from web.py is saved as .tar.bz2 from the browser. However when served by flask, the .bz2 extension is removed (but running file against the file still identifies it as a .bz2 file).
I have both frameworks running (web.py on python 2.7 and flask on python 3.7).
I manually put the same .tar.bz2 file in a directory and serve it from the web page.
Web.py:
=======
<form method="get" action="$fName">
<div id="formsubmitbutton">
<input type="submit" name="Retrieve File" value="Retrieve File" class="button3" />
</div>
</form>
Flask:
======
<form method="get" action="{{ fName }}">
<div id="formsubmitbutton">
<input type="submit" name="Retrieve File" value="Retrieve File" class="button3" />
</div>
</form>
I would expect both setups to return fName.tar.bz2. Chrome is returning the following and I have no clue why, but suspect it has something to do with my problem:
"Resource interpreted as Document but transferred with MIME type application/x-tar"
UPDATE
Thanks for the tip. From Chrome though, that was the entire error message, minus the actual file name since there is customer information in there. Here is is edited error:
Resource interpreted as Document but transferred with MIME type application/x-tar: "http://foo.example.com:5000/static/1564445156.7369618/filename.tar.bz2?Retrieve+SSD=Retrieve+SSD".
Also, there is no traceback from web.py or Flask, because there is no error. it's just that when you click on retrieve file, web.py returns the full filename with .bz2 extenstion, and Flask returns the file without the .bz2 extension.
The .bz2 files I am trying to serve are in the /static directory. By adding an app.route('/static') function, I was able to serve the file as a .bz2 without it being stripped of the .bz2 suffix:
#main.route('/static')
def sendfile():
for key,val in request.values.items():
filedir = '/home/admin/Flask/httsTools'+os.path.dirname(key)
filename = os.path.basename(key)
return send_from_directory(filedir, filename, as_attachment=True)
Whether or not this is the recommended way to do it I'm not sure, but it works.
Thank you for your help.
What is the simplest way to display the Python ystockquote (http://goldb.org/ystockquote.html) module output in HTML? I am creating an HTML dashboard which will be run locally on my computer and want to insert the stock output results into the designated HTML placeholders. I am hoping that because it is local I can avoid many CGI and server requirements.
I would use a templating system (see the Python wiki article). jinja is a good choice if you don't have any particular preferences. This would allow you to write HTML augmented with expansion of variables, control flow, etc. which greatly simplifies producing HTML automatically.
You can simply write the rendered HTML to a file and open it in a browser, which should prevent you from needing a webserver (though running python -m SimpleHTTPServer in the directory containing the HTML docs will make them available under http://localhost:8000)
Here is a simple server built using web.py (I have been playing with this for a while now, so this was a fun question to answer)
import web
import ystockquote
urls = (
'/', 'index'
)
app = web.application(urls, globals())
class index:
def POST(self):
history = ystockquote.get_historical_prices(web.input()['stock'], web.input()['start'], web.input()['end'])
head = history[0]
html = '<html><head><link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"><body><table class="table table-striped table-bordered table-hover"><thead><tr><th>{}<th>{}<th>{}<th>{}<th>{}<th>{}<th>{}<tbody>'.format(*head)
for row in history[1:]:
html += "<tr><td>{}<td>{}<td>{}<td>{}<td>{}<td>{}<td>{}".format(*row)
return html
def GET(self):
return """<html>
<head><link href='//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css' rel='stylesheet'>
<body>
<form method='POST' action='/'><fieldset>
Symbol <input type='input' name='stock' value='GOOG'/><br/>
From <input type='input' name='start' value='20130101'/><br/>
To <input type='input' name='end' value='20130506'/><br/>
<input type='submit' class='btn'/></fieldset></form>"""
if __name__ == "__main__":
app.run()