I'm tying to get an image attachment from couchdb using flask & python then pass the image to imgurl.html to be displayed.
The problem is that I'm only get this:
couchdb.http.ResponseBody object at 0x103b9c0b8> returned.
app.py
from flask import Flask, request, render_template, flash, request, url_for, redirect
import couchdb
import requests
app = Flask(__name__)
couch = couchdb.Server('http://127.0.0.1:5984/')
db = couch['test2']
doc = db.get_attachment('2', 'aboutme.jpg', default=None)
print("doc: ", doc)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/imgurl/')
def imgurl():
return render_template('imgurl.html', doc = doc)
#app.route('/page/')
def page():
return("Andrew Irwin")
#return render_template('index.html')
if __name__ == '__main__':
app.run()
test.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<img src="{{ doc }}" id="imgslot" >
<h1 id="h1id"> {{ doc }} </h1>
</body>
</html>
One option could be to base64 encode the image data returned from couchdb and pass the encoded data as a string to the template where you can render it. E.g.
img = db.get_attachment('2', 'aboutme.jpg', default=None).read()
img_b64 = base64.b64encode(img)
def imgurl():
return render_template('imgurl.html', doc = img_b64)
Then in the template:
<img src="data:image/png;base64,{{ doc }}" id="imgslot" >
Another option depending on your security model could be to serve the image directly from couchdb by adding the image url to the image tag, e.g. Getting url for an attachment
Before I saw #SHC's answer I managed to come up with a solution my self.
What I did was retrieve the name of the attachment and then append that to the end of a url like i.e "http:localhost:5984/dbName/docId/attachmentName".
I passed that url to the html img src and it worked then. Thank you you #SHC for your answer. sorry I didnt see it sooner.
Related
In Python I would like to render a python variable "myVariable" - which is already in my workspace - to an html template with flask. I just want to render one single html page to copy paste the source code and publish that on a webserver elsewhere. My code renders local variables but I cannot find a solution for passing workspace variables to the render function.
My template (home.html):
<html>
<head>
<title>Some title</title>
</head>
<body>
<p>My variable = {{ myVariable }}. </p>
</body>
</html>
My python code:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def somfun():
#myVariable = 12345 #**working... but how to use already existing workspace variable?**
return render_template("home.html", myVariable=myVariable)
if __name__ == '__main__':
app.run()
I've been following multiple Flask tutorials (but mostly this one) on creating a web app that I can use to read an image into a FastAi model. At some point, I was even able to get the images to upload into a folder, but I could never get them to display on the webpage itself no matter what I tried to do (refactor the function, move the folder to 'static', explicitly declare paths, etc.). I assume I'm probably missing something incredibly basic but I don't know enough about Flask and how web apps work to know what that is.
Edit: I keep getting 400 Bad Request pages every time I attempt to upload an image through the "index.html" page and the image doesn't appear in the folder when I inspect it with Windows Explorer.
file structure:
main.py
app
--> __init__.py
--> routes.py
main.py:
from app import app
main.py:
from flask import Flask
app = Flask(__name__)
from app import routes
routes.py:
from app import app
import os
from fastai.vision.widgets import *
from flask import Flask, render_template, request
#app.route('/', methods=['GET','POST'])
def index():
return render_template('index.html')
def get_predictions(img_path):
global learner_inf
learner_inf = load_learner('app/static/model/export.pkl')
return learn_inf.predict(img_path)
#app.route('/predict', methods=['GET','POST'])
def predict():
if request.method == 'POST':
file = request.files['file']
filename = file.filename
file_path = os.path.join('app/static/uploads', filename)
file.save(file_path)
result = get_predictions(file_path)
return render_template('predict.html', result = str(result), user_image = file_path)
index.html
<!doctype html>
<html>
<head>
<title>Grocery Classifier</title>
</head>
<body>
<h1>Grocery Classifier</h1>
<form method="POST" action="/predict" enctype="multipart/form-data">
<p><input type="file" name="file /"></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
predict.html
<!doctype html>
<html>
<head>
<title>Grocery Classifier</title>
</head>
<body>
<h1>Grocery Classifier</h1>
<img src="{{ user_image }}" alt="Selected Image" class="img-thumbnail">
<h2>{{ result }}</h2>
</body>
</html>
When referencing static items such as images and files, use the static folder to hold them.
app = Flask(__name__, static_folder="static")
After that, include it in CSS/HTML. This is not the direct application of inserting images in your situation, but it serves as a good example.
background-image: url("bg.gif");
The url to reference the image can be literally anything, just be sure to remember it for later reference. The reference "bg.gif" seen in the CSS automatically does GET request to "yoururl.com/bg.gif" to obtain the image.
Now link that url to the site path.
#app.route('/bg.gif', methods=['GET'])
def bghome():
return send_from_directory("static", "bg.gif")
The route MUST be correct and exact and the file MUST exist. If you use a kwarg to get the image url, be sure to keep that url consistent to what you define in your flask backend pathing.
I have a bunch of files in a directory that I wish to render and serve to the user, but have been unable to. Going to the path always returns just the 'page_template.htm' and not the rendered file. Here's my code:
from flask import Flask, request, render_template, send_from_directory
# Instantiate the Flask app
app = Flask(__name__)
app.config.from_object(__name__)
pages = FlatPages(app)
#app.route("/")
#app.route("/index")
def index():
return render_template('index.html')
#app.route("/Special_Data/<path:path>")
def page(path):
page = send_from_directory('Special_Data', path)
return render_template('page_template.htm', page=page)
What I wish to do is to grab raw text files from the 'Special_Data' directory and to render them into html files so they look nice, then send them to the user if they click on a link.
The files are in the directory 'Special_Data' and the 'page_template.htm' is in the 'templates' directory.
Where am I going wrong?
The following example shows you how you can use FlatPages to list, display and offer files for download. The markdown code is rendered beforehand and integrated into the specified or the default template.
from flask import Flask
from flask import render_template, send_file
from flask_flatpages import FlatPages
from io import BytesIO
import os
app = Flask(__name__)
# Optional configuration here!
pages = FlatPages(app)
# ...
# List all available pages.
#app.route('/contents')
def contents():
return render_template('contents.html', pages=pages)
# Display the rendered result.
#app.route('/page/<path:path>')
def page(path):
page = pages.get_or_404(path)
template = page.meta.get('template', 'flatpage.html')
return render_template(template, page=page)
# Download the rendered result.
#app.route('/download/<path:path>')
def download(path):
page = pages.get_or_404(path)
template = page.meta.get('template', 'flatpage.html')
return send_file(
BytesIO(str(render_template(template, page=page)).encode()),
as_attachment=True,
attachment_filename=f'{os.path.basename(path)}.html'
)
templates/contents.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<ul>
{% for page in pages %}
<li>
[Download] -
{{ page.title }}
</li>
{% endfor %}
</ul>
</body>
</html>
templates/flatpage.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ page.title }}</title>
</head>
<body>
{{ page }}
</body>
</html>
pages/Special_Data/ncs1.html
title: Hello
published: 2010-12-22
Hello, *World*!
Lorem ipsum dolor sit amet
If you want to use a different template for rendering, you can define one within the metadata based on the file name. Add the following below published and a suitable template within the templates folder.
template: mytemplate.html
The problem is, that send_from_directory sends the file to the client, it does not load it into memory. So your page variable is actually of type Response instead of str or a fileobject. If you want to read the file and than display it use
import werkzeug
...
#app.route("/Special_Data/<path:path>")
def page(path):
p = werkzeug.security.safe_join("Special_Data", path)
with open(p, "r", encoding="utf-8") as f:
return render_template('page_template.htm', page=f.read())
Otherwise I'm afraid I can't help as I don't know what you want to do.
Using send_from_directory Return a file to client.
So, you need to change like this
#app.route("/Special_Data/<path:path>")
def page(path):
return send_from_directory('Special_Data', path)
Or
return send_file(filename_or_fp=file_path, as_attachment=True, add_etags=True, conditional=True)
render_template will render your html template, it may return a html string. Therefore you need return file instead HTML string
I made a simple Flask app where I can upload a file on a web page and it gets saved on my PC. I am able to upload files using browser.
This is the Web page Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
{{ form.csrf_token }}
{{ form.images }}
<button type="submit">Upload</button>
</form>
</body>
</html>
And This is the Flask App Code
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import FileField
from flask_uploads import configure_uploads, IMAGES, UploadSet
app = Flask(__name__, template_folder="templates")
app.config["SECRET_KEY"] = "secret"
app.config["UPLOADED_IMAGES_DEST"] = "img"
images = UploadSet("images", IMAGES)
configure_uploads(app, images)
class MyForm(FlaskForm):
images = FileField("images")
#app.route("/", methods = ["GET", "POST"])
def index():
if form.validate_on_submit():
print(form.images.data)
filename = images.save(form.images.data)
return f"Fileame: { filename }"
return render_template("template.html", form = MyForm())
You can use something like this. It will forward to another server. warning there is poor error checking here. This will upload from flask to flask server.
#route('/', methods=['GET', 'POST'])
def index(self):
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST':
uploaded_file = request.files['file']
task_id = random.getrandbits(16)
if not uploaded_file:
logging.info("[+] No tweet data supplied.")
return render_template('index.html')
try:
response = requests.post("{}/".format("www.someotherhost.com"), files={'file': (uploaded_file.filename, uploaded_file.stream, uploaded_file.content_type, uploaded_file.headers)})
if response != "Success":
print("do something here.")
except Exception as error:
logging.info("[-]", str(error))
return render_template('index.html')
return redirect(url_for('view:get_task_status', task_id=task_id))
Pass a files argument to the requests.post method which should be a dictionary where the key is 'images' as defined in your server app, and the value is the file pointer:
import requests
def upload(filename):
headers={'ContentType': 'multipart/form-data'}
with open(filename,'rb') as f:
files = {'images': f}
url='http://localhost:5000/'
r = requests.post(url, files=files)
print (r.content, r.status_code)
upload('some_file.jpg')
This question already has answers here:
Get the data received in a Flask request
(23 answers)
Closed 2 years ago.
I'm new to flask and web programming in general. I'm trying a simple example. I have a HTML base template that shows a text box and a picture of an animal. The template is rendered by flask. The idea is that a user can type the name of a new animal in the text box and the picture changes to the new animal.
I tested the code. There is a problem - that the input text given in the html textbox doesn't seem to go to the proper app.route. Or at least I can't figure out (as I'm running on pythonanywhere and the print statements in the server don't show up on console).
Here is the code and the template. Please let me know what I'm doing wrong. Thanks!
Here is the flask_app.py:
from flask import render_template
from flask import request, redirect
from flask import Flask
app = Flask(__name__)
#app.route('/')
def index():
imgname = "tiger2.png"
return render_template('untitled1.html', title='TIGER', fname=imgname)
#app.route('/', methods=['POST', 'GET'])
def imgshow(animal):
#assert request.method == 'POST'
#print("New request!")
animal = request.form['animal']
if animal.lower() == 'tiger':
imgname = 'tiger2.png'
elif animal.lower() == 'lion':
imgname = 'lion1.png'
elif animal.lower() == 'panther':
imgname = 'panther.png'
else:
imgname = 'lion1.png'
return render_template('untitled1.html', title=animal.upper(), fname=imgname)
And here is the template untitled1.html
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<!-- Serving an Image -->
<h1>Hello, World!</h1>
<form action="">
<label for="animal">Animal: </label>
<input type="text" id="animal" name="animal"><br><br>
</form>
<img src="{{ url_for('static', filename=fname ) }}" alt="Tiger">
</body>
</html>
Try this:
from flask import render_template
from flask import request, redirect
from flask import Flask
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
imgname = "tiger2.png"
title='TIGER'
else:
variants = {
'tiger': 'tiger2.png',
'lion': 'lion1.png',
'panther': 'panther.png'
}
animal = request.form.get('animal').lower()
imgname = variants.get(animal)
title = animal.upper()
return render_template('untitled1.html', title='TIGER', fname=imgname)
For me, the best approach is to use only the GET method:
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
animals = {'tiger': 'tiger2.png', \
'lion': 'lion1.png', \
'panther': 'panther.png'}
#app.route('/')
def index():
animal = request.args.get('animal', 'tiger')
image = animals.get(animal, 'lion')
return render_template('untitled1.html', title=animal.upper(), fname=image)
The POST method is best when you need to do some processing (write data from the database) and then redirect to another GET route.
app.route registers that under the given web address (in your case \), the function listed just below be implemented. The problem is that you have two functions registered under the same route which means that the first registration is erased.
You don't need the first app.route. It basically should say that the default value of an animal is a tiger. The second function should be modified as below:
display_map = {
'tiger': 'tiger2.png',
'lion': 'lion1.png',
'panther': 'panther.png'
}
#app.route('/', methods=['POST', 'GET'])
def imgshow(animal):
if request.method == 'POST':
animal = request.form.get('animal', 'lion').lower()
imgname = display_map.get(animal, 'lion1.png')
return render_template('untitled1.html', title=animal.upper(), fname=imgname)
else:
return render_template('untitled1.html', title='TIGER', fname='tiger.png')
And you also need to actually submit results to the server.
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<!-- Serving an Image -->
<h1>Hello, World!</h1>
<form method="POST">
<label for="animal">Animal: </label>
<input type="text" id="animal" name="animal"><br><be>
<input type="submit" name="submit" value="submit">
</form>
<img src="{{ url_for('static', filename=fname ) }}" alt="Tiger">
</body>
</html>