I'm updating on updating an older project that uses AJAX and have decided to use Flask to do so. For the particular page I'm currently working on, I need to be able to upload a CSV and read the data in the file (no need to save it). I have several other pages that work using AJAX, but they return form data back to Flask (e.g. what semester it is, what year it is, etc). Ideally, I'd like to be able to upload the CSV and read the form data (the variables I have called formData and myFormData below).
I have found this post and based my MWE on it, but when I look at request.files, I get an empty dictionary. Here is the code I have:
run.py:
import os
from app import app
if __name__ == "__main__":
port = int(os.environ.get("PORT", 5000))
app.run(host='0.0.0.0', port=port, debug=True)
__init__.py:
from flask import Flask, session
import flask_excel as excel
from fileUpload import fileUpload_bp
def create_app():
app = Flask(__name__, template_folder="templates")
app.secret_key = 'flask-ajax file upload test'
app.register_blueprint(fileUpload_bp)
excel.init_excel(app)
return app
app = create_app()
file_upload.py:
from flask import Flask, render_template, request, Blueprint
fileUpload_bp=Blueprint('fileUpload',__name__)
#fileUpload_bp.route('/fileUpload',methods=['GET','POST'])
def fileUpload():
if request.method=="POST":
print(request.files)
return render_template("fileUpload.html")
fileUpload.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>file upload test</title>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript"
src="static/scripts/fileUpload.js"></script>
</head>
<body>
<form action="javascript:fileUpload()" method="POST" enctype="multipart/form-data">
<input type="file" id="file_upload_data"><br>
<input type="text" id="form_data" value="sample data">
<button type="submit">Upload</button>
</form>
</body>
</html>
fileUpload.js:
function fileUpload()
{
var formData=new FormData($("file_upload_data")[0]);
var myFormData={form_data: $("#form_data").val()};
$.ajax({
type: 'post',
dataType: 'html',
url: 'fileUpload',
async: false,
data: formData,
contentType: false,
cache: false,
processData: false,
success: function (data){
console.log('Success');
},
error: function(response, status, xml) {
console.log('failure');
}
});
}
A little additional info: This is part of a larger project which is why I'm using Blueprints and flask_excel. I've seen folks recommend using something other than AJAX, but I'm trying to make the pages run with python3 by using Flask without rewriting everything that's already there.
So that the form can be serialized, it is necessary for the input fields to have a name attribute.
I'm using the form's submit event in the following minimal example. The event listener is registered when the document is fully loaded. When the form is submitted, the form data is serialized and sent via ajax.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Upload</title>
</head>
<body>
<form name="upload-form" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// Register the listener for submit events.
$('form[name="upload-form"]').submit(function(evt) {
// Prevent the form from default behavior.
evt.preventDefault();
// Serialize the form data. The entire form is passed as a parameter.
const formData = new FormData($(this)[0]);
// Send the data via ajax.
$.ajax({
type: 'post',
url: '/upload',
data: formData,
contentType: false,
cache: false,
processData: false,
}).done(function(data) {
console.log('success');
}).fail(function(xhr, status, error) {
console.error('error');
});
});
});
</script>
</body>
</html>
The server-side code remains essentially the same. However, I advise you, for reasons of cleanliness, to separate endpoints for ajax requests from those that return html.
from flask import Flask
from flask import make_response, render_template, request
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload', methods=['POST'])
def upload():
print(request.files)
return make_response('', 200)
Related
I'm trying to implement a web push notification in my project. Using some tutorials I got create an alert on index page when I post a message. But it's far from being what I want.
index.html
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1>Testing...</h1>
</body>
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<script type="text/javascript">
var source = new EventSource('/stream');
source.onmessage = function (event) {
alert(event.data);
};
</script>
</html>
post.html
<html>
<head>
<title>Posting a Message</title>
</head>
<body>
<form action="{{url_for('post')}}" method='post'>
Message: <input type="text" name="message" size='50'> <input type="submit" value="Launch!">
</form>
</body>
</html>
app.py
#!/usr/bin/env python
from flask import Flask, render_template, request, session, Response
from redis import Redis
import datetime
app = Flask(__name__)
app.secret_key = 'asdf'
red = Redis(host='localhost', port=6379, db=0)
def event_stream():
pubsub = red.pubsub()
pubsub.subscribe('notification')
for message in pubsub.listen():
print message
yield 'data: %s\n\n' % message['data']
#app.route('/post', methods=['POST','GET'])
def post():
if request.method=="POST":
message = request.form['message']
now = datetime.datetime.now().replace(microsecond=0).time()
red.publish('notification', u'[%s] %s: %s' % (now.isoformat(), 'Aviso', message))
return render_template('post.html')
#app.route('/stream')
def stream():
return Response(event_stream(),
mimetype="text/event-stream")
#app.route('/')
def index():
return render_template('index.html')
if __name__=="__main__":
app.run(host='0.0.0.0', port=8001, debug=True,threaded=True)
Well, I would like to implement a subscribe system, I think that is how is called. The user allow to receive notification from the website and when he clicks on the "news" it opens a new page with the detailed content.
The index page does not need to be opened for receving the message.
I've spent all day tinkering with this app trying to get some simple information passed to the back end of the application. I am using a simple flask app and trying to send data from a search query to the back end using ajax. However, I have been completely unsuccessful. Any help would be greatly appreciated.
Below is app.py
from scraper import scrape
from flask import Flask, render_template, jsonify, make_response, request
import json
app = Flask(__name__)
#app.route("/")
def index():
entries = json.dumps(scrape("video games"))
return render_template('index.html', entries= entries)
#app.route('/parse_data', methods=['GET', 'POST'])
def parse_data():
if request.method == "GET":
#data = request.form("blah")
#print("blah")
search = request.json
#new_search = json.dumps(scrape(data))
return search
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5000)
and index.html
<!DOCTYPE html>
<html>
<head>
<title>Flask app</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div class="topnav">
<a class="active" href="#home">Home</a>
About
Contact
<form name = "textbox" id = "textbox">
<input id ="textbox" name="textbox" type="text" placeholder="Search..">
<button type="submit">submit</button>
</form>
</div>
<p>you searched: {{search}} </p>
<div id="div1">
<p id="p1"></p>
<p id="p2"></p>
</div>
<script>
var value = $('.textbox').val();
//alert(value);
$.ajax({
type: 'POST',
url: "/parse_data",
data: JSON.stringify(value)
contentType: 'application/json',
success: function(data){
alert("success")
}
});
var jsonz = {{ entries|tojson }};
var s = JSON.parse(jsonz);
var i;
for (i = 0; i < s.length; i++) {
var para = document.createElement("p");
var node = document.createTextNode(s[i].product_name + "\n" + s[i].product_link);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
}
//document.getElementById("user").innerHTML =
//obj;
//"Name: " + obj.product_name + "<br>" +
//"Location: " + obj.product_link;
</script>
</body>
</html>
Your code snippet has a few issues, mostly:
Your AJAX request is not bind to the button click event, so clicking the button does nothing.
You have two html elements with the same id textbox, id are supposed to be unique.
To get an html element by id use "#textbox"
On the server side (Flask):
Use the function get_json() of the request
To process the POST request you need to check for POST not GET
Try wrapping your POST request like this:
$("button").click(function (e) {
e.preventDefault();
var value = $("#textbox").val();
alert(value);
$.ajax({
type: "POST",
url: "parse_data",
data: JSON.stringify({ "text" : value } ),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert(JSON.stringify(data));
}
});
});
Also remove the duplicate ids textbox, change the id of the form to something like textbox-form, finally change your parse_data function to something like this:
#app.route('/parse_data', methods=['GET', 'POST'])
def parse_data():
if request.method == 'POST':
search = request.get_json()
return jsonify(search)
return render_template('index.html')
I am trying to upload an image about 1.62MB to an end point written using flask. the request.files object is always empty. I've checked the following questions but no luck:
Flask request.files is empty
https://github.com/requests/requests/issues/2505
How to upload a file using an ajax call in flask
here is my server:
from flask import Flask, request, jsonify, render_template
import sys
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = r"C:\Temp"
app.debug = True
#app.route("/demo-upload", methods=["GET", "POST"])
def ProcessImage():
if request.method == "POST":
print(request.files)
try:
if 'file' in request.files:
with open("test-upload.png", "wb") as iFile:
print(request['file'])
iFile.write(request.files['file'])
except Exception as e:
print(e)
return jsonify("Ok")
#app.route("/", methods=["GET"])
def DemoIndexPage():
return render_template("index.html")
if __name__ == "__main__":
app.run()
my client:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<script src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<title>Demo</title>
</head>
<body>
<h1 style="text-align: center">Status Demo</h1>
<span>upload image to process.</span><br/>
<form id="FileForm" name="file" enctype="multipart/form-data">
<input type="file" name="file" id="File" />
<input type="button" name="submit" value="submit" onclick="ProcessImage()" />
</form>
<p id="status" hidden>Success!</p>
<script>
function ProcessImage()
{
var form_data = new FormData($('#File')[0]);
console.log(form_data)
$.ajax({
type: 'POST',
url: '/demo-upload',
data: form_data,
contentType: false,
cache: false,
processData: false,
async: false,
success: function (data) {
console.log('Success!');
$("#status").show();
},
});
}
</script>
</body>
</html>
everything looks clean to me and I do not know where I am going wrong. the files attribute in the request object is always empty. I also tried with postman using post request with form-data key = file and value = uploaded a file, and a header content-type = "multipart/form-data". any help is appreciated thanks a lot!
I made a few changes and make it work:
First, change which html element you read the data from in javascript part:
var formDataRaw = $('#FileForm')[0];
var form_data = new FormData(formDataRaw);
Second, I tried to obtain the uploaded image as follows: (#cross_origin() is only required if you try to upload to your localhost)
#app.route("/demo-upload", methods=["GET", "POST"])
#cross_origin()
def ProcessImage():
if request.method == "POST":
print(request.files)
try:
if 'file' in request.files:
imageFile = request.files['file']
savePath = "/somewhere/somewhere/something.png"
imageFile.save(savePath)
except Exception as e:
print(e)
return jsonify("Ok")
So I was starting out with Flask and thought of creating a Youtube search engine wherein I will be taking data from the user through Html from and send that data to Flask using Ajax.
Here is the code for my index html page:
{% extends "layout.html" %}
{% block content %}
<script type=text/javascript>
$(function() {
$("#echoText").keyup(function() {
$.ajax({
type: "GET",
url: $SCRIPT_ROOT + "/echo/",
contentType: "application/json; charset=utf-8",
data: { echoValue: $('input[name="echoText"]').val() },
success: function(data) {
$('#echoResult').text(data.value);
}
});
});
});
</script>
<strong>Enter a value to echo back:</strong>
<input type='text' size='10' id='echoText' name='echoText'>
<button type='button' id='submitBtn' name='submitBtn'>Submit via AJAX</button><br /><br />
<div id='echoResult'></div>
{% endblock %}
And here is my flask app python file:
from flask import Flask, jsonify, render_template, request
import youtube
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/echo/', methods=['GET'])
def echo():
ret_data = {"value":youtube.youtube_search(request.args.get('echoValue'))[1][0]["id"]["videoId"]}
data = jsonify(ret_data)
return data
if __name__ == '__main__':
app.run(port=5000, debug=True)
So right now I am able to transfer the data from Html page to flask but I some how want to use the data return a YouTube video embedded in my Html page. How can I do that?
I am just learning Flask. I am trying to get a JSON object through a jQuery call into flask. My html look like this,
<html>
<head>
<title>Passenger</title>
<style type="text/css"></style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div>
<form onsubmit="return false">
<input class="name" type="text" placeholder="Name">
<input class="submit" type="submit" placeholder="Go">
</form>
</div>
<script>
$("input.submit").click(function(e){
$.post( "/save", {name: $("input.name").val(), time: "2pm"});
});
</script>
</body>
</html>
The Flask app file looks like,
from flask import Flask
from flask import redirect, url_for, jsonify
from flask import request
import json
app = Flask(__name__)
#app.route('/')
def home():
return redirect(url_for('static',filename='index.html'))
#app.route('/save', methods=['PUT','POST'])
def get_name():
print request.json
return request.json
if __name__=='__main__':
app.run(debug=True)
Running this code returns None. I am expecting to get back the JSON object [{name: $("input.name").val(), time: "2pm"}]. Thanks.
The problem is that the jquery post is not using the data type of json. You can see that by printing out the request content_type:
print request.content_type
application/x-www-form-urlencoded; charset=UTF-8
Change the Javascript to post json, and request.json should be populated with json as you expect.
var data = JSON.stringify({name: $("input.name").val(), time: "2pm"});
$.ajax("/save", {
data: data,
contentType : "application/json",
type : "POST"
});
Notice that after changing the JS code, request.content_type will be application/json