Getting JSON data in Flask function - python

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

Related

How to upload a (csv) file with an AJAX call and Flask

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)

werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (orproxy) sent a request that this server could not understand. KeyError: 'file1' [duplicate]

This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
Closed 1 year ago.
Python code
from flask import Flask, app, render_template, request
app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 1
#app.route('/')
def index():
return render_template('index.html')
#app.route('/after', methods=['GET', 'POST'])
def after():
file = request.files['file1']
file.save('static/file.jpg')
return render_template('predict.html')
if __name__ == '__main__':
app.run(debug = True)
following is html code from 'index.html':
<html>
<form action="{{url_for('after')}}">
<input type= "submit" enctype = 'multipart/form-data' method ="POST">
<input type="file" name='file1'>
</form>
</html>
And follwing is the code from 'predict.html'
<html>
<body>
<img src="{{url_for('static', filename = 'file.jpg')" alt="">
</body>
</html>
I am trying to choose an image file by clicking on 'Choose file' button to submit it but while doing this I got the following error;
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'file1"
Set the enctype and method attributes for your form tag, not for input:
<html>
<form action="{{url_for('after')}}" enctype="multipart/form-data" method="POST">
<input type="submit">
<input type="file" name="file1">
</form>
</html>

Python flask upload file using ajax request.files empty

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")

How to use data provided by Ajax in flask?

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?

Method Not Allowed flask error 405

I am developing a flask registration form, and I receive an error:
error 405 method not found.
Code:
import os
# Flask
from flask import Flask, request, session, g, redirect, url_for, abort, \
render_template, flash, Markup, send_from_directory, escape
from werkzeug import secure_filename
from cultura import app
# My app
from include import User
#app.route('/')
def index():
return render_template('hello.html')
#app.route('/registrazione', methods=['POST'])
def registration():
if request.method == 'POST':
username= request.form.username.data
return render_template('registration.html', username=username)
else :
return render_template('registration.html')
registration.html:
<html>
<head> <title>Form di registrazione </title>
</head>
<body>
{{ username }}
<form id='registration' action='/registrazione' method='post'>
<fieldset >
<legend>Registrazione utente</legend>
<input type='hidden' name='submitted' id='submitted' value='1'/>
<label for='name' >Nome: </label>
<input type='text' name='name' id='name' maxlength="50" /> <br>
<label for='email' >Indirizzo mail:</label>
<input type='text' name='email' id='email' maxlength="50" />
<br>
<label for='username' >UserName*:</label>
<input type='text' name='username' id='username' maxlength="50" />
<br>
<label for='password' >Password*:</label>
<input type='password' name='password' id='password' maxlength="50" />
<br>
<input type='submit' name='Submit' value='Submit' />
</fieldset>
</form>
</body>
</html>
when I visit localhost:5000/registrazione, I receive the error. What am I doing wrong?
This is because you only allow POST requests when defining your route.
When you visit /registrazione in your browser, it will do a GET request first. Only once you submit the form your browser will do a POST. So for a self-submitting form like yours, you need to handle both.
Using
#app.route('/registrazione', methods=['GET', 'POST'])
should work.
change name of method registration
#app.route('/registrazione', methods=['POST'])
def registrazione():
if request.method == 'POST':
username= request.form.username.data
return render_template('registration.html', username=username)
else :
return render_template('registration.html')
Just for people reading on it now.
You have to render the /registrazione first, befor you can access the form data. Just write.
#app.route("/registrazione")
def render_registrazione() -> "html":
return render_template("registrazione.html")
before you define def registration(). Sequence is key. You can't access data before the even are available. This is my understanding of the problem.
For the error 500 (internal server error) in
username = request.form.username
write instead
username = request.args.get("username")
Example of a flask app using wsgi with JQuery, Ajax and json:
activecalls.py
from flask import Flask, jsonify
application = Flask(__name__, static_url_path='')
#application.route('/')
def activecalls():
return application.send_static_file('activecalls/active_calls_map.html')
#application.route('/_getData', methods=['GET', 'POST'])
def getData():
#hit the data, package it, put it into json.
#ajax would have to hit this every so often to get latest data.
arr = {}
arr["blah"] = []
arr["blah"].append("stuff");
return jsonify(response=arr)
if __name__ == '__main__':
application.run()
Javascript json, /static/activecalls/active_calls_map.html:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<script>
$.ajax({
//url : "http://dev.consumerunited.com/wsgi/activecalls.py/_getData",
url : "activecalls.py/_getData",
type: "POST",
data : formData,
datatype : "jsonp",
success: function(data, textStatus, jqXHR)
{
//data - response from server
alert("'" + data.response.blah + "'");
},
error: function (jqXHR, textStatus, errorThrown)
{
alert("error: " + errorThrown);
}
});
</script>
When you run this. The alert box prints: "stuff".
I was also getting this error, I was going through all of this documentation and trying to sort this out, but at the end it was a silly mistake.
Below code was generating the 405 Method Not Allowed error
import requests
import json
URL = "http://hostname.com.sa/fetchdata/"
PARAMS = '{ "id":"111", "age":30, "city":"New Heaven"}'
response = requests.post(url = URL, json = PARAMS)
print(response.content)
It was due to an extra / at the end of url, when I removed it, it was gone. The below update on the requesting URL fixed it
URL = "http://hostname.com.sa/fetchdata"
I was stuck over same issue, I am showing my Login page route as default route and when I try to submit with default route then I got the issue because I had configured POST request on login route but not on the default application route and when I had added the 'POST' method configuration for my default route too, everything is working as expected. The configuration I had done is as follows:
#routes.route("/", methods=['GET', 'POST'] )
#routes.route("/admin-login", methods=['GET', 'POST'])
def admin_login():
...
Hope, this would help anyone facing the similar issue.

Categories