I am new to flask and web development. I want to display an image on a local web server after I press a button on the webpage. I am using Flask.Ive been trying to figure this out for a while and havent been able too so any help would be incredible.
FLASK CODE:
#app.route('/graph_select')
def graph_select():
return render_template('live_stream.html')
#app.route('/read_ph', methods=["GET"])
def ph_plot():
if request.method == "GET":
all_plots.ph_plot()
return render_template('live_stream.html')
#app.route("/read_temp", methods=["GET"])
def temp_plot():
if request.method == "GET":
all_plots.temperature_plot()
return render_template('live_stream.html')
#app.route('/read_distance', methods=["GET"])
def distance_plot():
if request.method == "GET":
all_plots.distance_plot()
return render_template('live_stream.html')
HTML CODE:
<h1>Data Monitoring Station</h1>
<form method="GET"
<button type="button">Temperature Graph</button>
<button type="button">PH Graph</button>
<button type="button">Distance Graph</button>
</form>
<h3><img src="{{ url_for('static', filename='ph_plot.png') }}" width="30%">$
<h3><img src="{{ url_for('static', filename='temperature_plot.png') }}" width="30%">$
<h3><img src="{{ url_for('static', filename='distance_plot.png') }}" width="30%">$
</body>
</html>
TLDR;
I wrote a minimal example on displaying images on button click using Flask and Ajax.
In essence, I just returned the URL of the image to the HTML page and set the src attribute of <img> tag with the returned URL.
app.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def hello():
return render_template('a.html')
#app.route("/getimage")
def get_img():
return "a.jpg"
if __name__ == '__main__':
app.run()
a.html:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<button type='button' id ='retrieve'>Submit</button>
<img src="" id="myimg" />
</body>
<script>
$(document).ready(function() {
$('#retrieve').click(function(){
$.ajax({
url: "{{ url_for ('get_img') }}",
type: "GET",
success: function(response) {
$("#myimg").attr('src', '/static/' + response);
},
error: function(xhr) {
//Do Something to handle error
}
});
});
});
</script>
</html>
You can modify this code as you wish.
Note: The a.html file should be in templates folder and the a.jpg file should be in the static folder.
Hope this helps. Good luck.
Related
I am creating an API using FastAPI, which receives form-data from an HTML page, process the data (requiring a few moments) and returns a message saying this task is complete.
This is my backend:
from cgi import test
from fastapi import FastAPI, Form, Request
from starlette.responses import FileResponse
app = FastAPI()
#app.post("/")
async def swinir_dict_creation(request: Request,taskname: str = Form(...),tasknumber: int = Form(...)):
args_to_test = {"taskname":taskname, "tasknumber":tasknumber} # dict creation
print('\n',args_to_test,'\n')
# my_function_does_some_data_treatment.main(args_to_test)
# return 'Treating...'
return 'Super resolution completed! task '+str(args_to_test["tasknumber"])+' of '+args_to_test["taskname"]+' done'
#app.get("/")
async def read_index():
return FileResponse("index.html")
This is my frontend code:
<html>
<head>
<h1><b>Super resolution image treatment</b></h1>
<body>
<form action="http://127.0.0.1:8000/" method="post" enctype="multipart/form-data">
<label for="taskname" style="font-size: 20px">Task name*:</label>
<input type="text" name="taskname" id="taskname" />
<label for="tasknumber" style="font-size: 20px">Task number*:</label>
<input type="number" name="tasknumber" id="tasknumber" />
<b><p style="display:inline"> * Cannot be null</p></b>
<button type="submit" value="Submit">Start</button>
</form>
</body>
</head>
</html>
So the frontend page looks like this:
When the processing is finished in the backend, after the user submitted some data, the return statement from FastAPI backend simply redirects the user to a new page showing only the return message. I was looking for a alternative that would keep the HTML form appearing and display the message returned from the server below this form. For example:
I searched in FastAPI documentation about requests, but I haven't found anything that could avoid modifying my original HTML page.
You would need to use a Javascript interface/library, such as Fetch API, to make an asynchronous HTTP request. Also, you should use Templates to render and return a TemplateResponse, instead of FileResponse, as shown in your code. Related answers can also be found here and here, which show how to handle <form> submission on the submit event, and prevent the default action that causes the page to reload. If you would like to post JSON data instead, have a look at this answer, while for posting both Files and Form/JSON data, have a look at this answer.
Working Example:
app.py
from fastapi import FastAPI, Form, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
#app.post("/submit")
async def submit(request: Request, taskname: str = Form(...), tasknumber: int = Form(...)):
return f'Super resolution completed! task {tasknumber} of {taskname} done'
#app.get("/")
async def index(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
templates/index.html
<!DOCTYPE html>
<html>
<body>
<h1>Super resolution image treatment</h1>
<form method="post" id="myForm">
<label for="taskname" style="font-size: 20px">Task name*:</label><br>
<input type="text" name="taskname" id="taskname"><br>
<label for="tasknumber" style="font-size: 20px">Task number*:</label><br>
<input type="number" name="tasknumber" id="tasknumber">
<p style="display:inline"><b>* Cannot be null</b></p><br><br>
<input type="button" value="Start" onclick="submitForm()">
</form>
<div id="responseArea"></div>
<script>
function submitForm() {
var formElement = document.getElementById('myForm');
var data = new FormData(formElement);
fetch('/submit', {
method: 'POST',
body: data,
})
.then(resp => resp.text()) // or, resp.json(), etc.
.then(data => {
document.getElementById("responseArea").innerHTML = data;
})
.catch(error => {
console.error(error);
});
}
</script>
</body>
</html>
I'm building a form with flask, below is the simplified version of my flask server
app = Flask(__name__)
#app.route("/", methods = ["POST", "GET"])
def main_page():
if request.method == "POST":
# some cool stuff
return render_template("main.html")
if __name__ == "__main__":
app.debug = True
app.run()
The problem is that it re-renders the page when the user submits the form, jumping to the top of the page. That makes the user experience kinda bad.
How to get the data of the form without re-rendering the entire page?
If you want to submit the form data, but don't want to completely re-render the page, your only option is to use AJAX.
In the following example, the form data is sent using the Fetch API. The processing on the server remains essentially the same because the form data is submitted in the same format.
However, since there is usually a response in JSON format here, I advise outsourcing the endpoint, so that there is a separation between HTML and JSON routes.
from flask import (
Flask,
jsonify,
render_template,
request
)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload', methods=['POST'])
def upload():
# Same cool stuff here.
print(request.form.get('data'))
return jsonify(message='success')
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
</head>
<body>
<form name="my-form" method="post">
<input type="text" name="data" />
<input type="submit" />
</form>
<script type="text/javascript">
(uri => {
// Register a listener for submit events.
const form = document.querySelector('form[name="my-form"]');
form.addEventListener('submit', evt => {
// Suppress the default behavior of the form.
evt.preventDefault();
// Submit the form data.
fetch(uri, {
method: 'post',
body: new FormData(evt.target)
}).then(resp => resp.json())
.then(data => {
console.log(data);
// Handle response here.
});
// Reset the form.
evt.target.reset();
});
})({{ url_for('upload') | tojson }});
</script>
</body>
</html>
How can python / flask block foreign form injections?
Consider the following mwe:
app.py
from flask import Flask, request, render template
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def helloworld():
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST':
print(request.form['info'])
## do something with the info, like write to a database
return 'nothing'
if __name__ == '__main__':
app.run(debug=True)
templates/index.html
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type='text/javascript' src="{{ url_for('static', filename='js/fire.js') }}"></script>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
static/js/fire.js
$(document).click(function() {
// post data to flask
$.post('/', {'info': 'test'});
return false;
};
My questions are:
Is injection possible from a foreign website? Follow-up: how could this be done? (e.g., perhaps via a form that posts to my website url?)
If injection is possible, what can I do in the app.py script to block the injection?
Edit
Here is a very basic script that can be used to test injections against the above flask application. The accepted answer blocks this script:
<!DOCTYPE html>
<html>
<body>
<h2>Malicious Form Injection</h2>
<form action='http://127.0.0.1:5000/' method='post'>
Input 1:<br>
<input name="info" value="mal1"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
app.py
from flask import Flask, request, render template
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
CSRFProtect(app)
app.config['SECRET_KEY'] = 'somethignrandom'
#app.route('/', methods=['GET','POST'])
def helloworld():
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST': # anything post will autocheck csrf
print(request.form['info'])
## do something with the info, like write to a database
return 'nothing'
if __name__ == '__main__':
app.run(debug=True)
There is no need to pass the secret key to the html template, as CSRFProtect will automatically pass the secret key.
templates/index.html
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<meta name='csrf-token' content="{{ csrf_token() }}">
<script type='text/javascript' src="{{ url_for('static', filename='js/fire.js') }}"></script>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
script.js
$(document).click(function() {
// post data to flask
$.post('/', {'info': 'test', '_csrf_token':$('meta[name="csrf-token"]').attr('content')});
return false;
};
I want to use Dropzone.js with Flask. After uploading file i want save file and show uploaded file name in another page (after redirect). But in browser i receive file name equals "sample_value". How to fix this?
Python
import os
from flask import Flask, render_template, request,redirect, url_for
app = Flask(__name__)
app.config['UPLOADED_PATH'] = os.getcwd() + '/upload'
#app.route('/')
def index():
# render upload page
return render_template('index.html')
#app.route('/upload', methods=['GET', 'POST'])
def upload():
n='sample_value'
if request.method == 'POST':
for f in request.files.getlist('file'):
n=f.filename
f.save(os.path.join(app.config['UPLOADED_PATH'], f.filename))
print(f.filename)
# There i get real file name
n=f.filename
return redirect(url_for('found', file_name=n), code=307)
#app.route('/found',methods=['GET', 'POST'])
def found():
#There my file name is "sample_value"
print('File name after redirect ', request.args.get('file_name'))
return request.args.get('file_name')
if __name__ == '__main__':
app.run(host='0.0.0.0', port =5000, debug=True, threaded=True)
Template
<html>
<body>
<script src="{{ url_for('static', filename='js/dropzone.js') }}"></script>
<script src="{{ url_for('static', filename='js/jquery.js') }}"></script>
<form action="{{ url_for('upload') }}" class="dropzone" id="my-dropzone" method="POST" enctype="multipart/form-data">
</form>
<script>
Dropzone.autoDiscover = false;
$(function() {
var myDropzone = new Dropzone("#my-dropzone");
myDropzone.on("queuecomplete", function(file) {
// Called when all files in the queue finish uploading.
window.location = "{{ url_for('upload') }}";
});
})
</script>
</body>
</html>
How i understand redirection executes before processing request?
I assume that you do not specify the method in your Dropzone, then it uses GET method by default. Check the Dropzone documentation and specify the method as POST.
n="sample_value"
if request.method == 'POST': # This is always false.
...
>>> print(n) # n has never been replaced
sample_value
I'm a beginner in front end development, and have to do a small web app in Flask for a project.
I have written a Flask app that lets you upload an image using HTML Forms and then displays the image back to the user when you hit Upload. I need to modify this such that the image does not get saved to a folder in the project directory everytime a user uploads it. Basically, the app should send the uploaded image back in the body of the response.
Here is my code so far:
UploadTest.py
import os
from uuid import uuid4
from flask import Flask, request, render_template, send_from_directory
app = Flask(__name__)
# app = Flask(__name__, static_folder="images")
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#app.route("/")
def index():
return render_template("upload.html")
#app.route("/upload", methods=["POST"])
def upload():
target = os.path.join(APP_ROOT, 'images/')
print(target)
if not os.path.isdir(target):
os.mkdir(target)
else:
print("Couldn't create upload directory: {}".format(target))
print(request.files.getlist("file"))
for upload in request.files.getlist("file"):
print(upload)
print("{} is the file name".format(upload.filename))
filename = upload.filename
destination = "/".join([target, filename])
print ("Accept incoming file:", filename)
print ("Save it to:", destination)
upload.save(destination)
return render_template("complete.html", image_name=filename)
#app.route('/upload/<filename>')
def send_image(filename):
return send_from_directory("images", filename)
if __name__ == "__main__":
app.run(port=8080, debug=True)
upload.html - creates an upload form
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</head>
<body>
<form id="upload-form" action="{{ url_for('upload') }}" method="POST" enctype="multipart/form-data">
<strong>Files:</strong><br>
<input id="file-picker" type="file" name="file" accept="image/*" multiple>
<div id="msg"></div>
<input type="submit" value="Upload!" id="upload-button">
</form>
</body>
<script>
$("#file-picker").change(function(){
var input = document.getElementById('file-picker');
for (var i=0; i<input.files.length; i++)
{
var ext= input.files[i].name.substring(input.files[i].name.lastIndexOf('.')+1).toLowerCase()
if ((ext == 'jpg') || (ext == 'png'))
{
$("#msg").text("Files are supported")
}
else
{
$("#msg").text("Files are NOT supported")
document.getElementById("file-picker").value ="";
}
}
} );
</script>
</html>
complete.html - displays the image from the folder in which it has been saved after a user hits "upload"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Uploaded
<img src=" {{url_for('send_image', filename=image_name)}}">
</body>
</html>
I have tried researching quite a bit but was unable to find anything other than deleting the folder after it has been displayed (which I didn't think is the right way of solving the question at hand). I'd really appreciate any help in this matter, and if there is a better solution than what my code currently does, I'd love to learn more!
Thank you! :)
Please check below code can help you.Copy the below code in upload.html in templates folder.
<!DOCTYPE html>
<html>
<head>
<link class="jsbin" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.min.js"></script>
<meta charset=utf-8 />
<script src="{{ url_for('static', filename='upload.js') }}"></script>
<style>
article, aside, figure, footer, header, hgroup,
menu, nav, section { display: block; }
</style>
</head>
<body>
<form action = "http://127.0.0.1:5000/uploader" method = "POST"
enctype = "multipart/form-data">
<input type='file' name = 'file' onchange="readURL(this);" />
<img id="blah" src="#" alt="your image" />
<input type = "submit"/>
</form>
</body>
</html>
Copy the below code in upload.js file in static folder
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#blah')
.attr('src', e.target.result)
.width(150)
.height(200);
};
reader.readAsDataURL(input.files[0]);
}
}
Now copy the below code in a python file
from flask import Flask, render_template, request
from werkzeug import secure_filename
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'D:/Projects/flask/image_upload/images/'
#app.route('/')
def upload_f():
return render_template('upload.html')
#app.route('/uploader', methods = ['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
f.save(os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename)))
return 'file uploaded successfully'
# if __name__ == '__main__':
app.run(debug = True)
Above piece of code will help you to browse and display the image on html page and as well save the image on your disk at desired location.
If you want to send back image to client there's 2 approach,
You can send image to client as an file url
You need to convert an image as blob or base64 image and show image