I'm trying to send an image file in a FormData using an Ajax POST request.
I am faced with 2 problems:
I do not know how to extract the FormData on the flask part
I 500 internal server error when making an ajax POST request (not sure if this is because of 1)
Thank you
Flask python code:
#app.route('/', methods=['GET','POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
if file: # and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(os.getcwd()+"/static", "current_image.jpg"))
return jsonify({'tasks': tasks})
HTML and Javascript code:
<input id="pictureInput" type=file name=file>
<input type=submit value=Upload id="button">
<script type="text/javascript">
var pictureInput = document.getElementById("pictureInput");
var myFormData = new FormData();
myFormData.append('pictureFile', pictureInput.files[0]);
$("#button").click(function(){
console.log(pictureInput);
console.log(pictureInput.files[0]);
console.log(myFormData);
$.ajax({
url: "http://localhost:8000/",
type: 'POST',
processData: false, // important
contentType: false, // important
dataType : 'json',
data: myFormData,
success : function(data){
console.log(data);
},
});
});
</script>
Error:
The following code should work for you. You need to have the static folder in the same level as your app.py file
app.py
import os
from flask import Flask, request, jsonify
from werkzeug.utils import secure_filename
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(os.getcwd()+"/static", "current_image.jpg"))
tasks = []
return jsonify({'tasks': tasks})
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
tasks is not defined above in your code, so I just initialized it to an empty list. You need also to make sure that jQuery is loaded in your template.
1. I do not know how to extract the FormData on the flask part
In order to extract the fomrdata, you could write the following code
#app.route('/', methods=['GET','POST'])
def upload_file():
if request.method == 'POST':
file = request.files['pictureFile'] # according to the name you append to formdata
2. I 500 internal server error when making an ajax POST request (not sure if this is because of 1)
Actaully, if the file is not be found, there is no correct response, so it will not work correctly.
You could reference the following sample code
#app.route('/', methods=['GET','POST'])
def upload_file():
if request.method == 'POST':
isSuccess = False
if 'file' not in request.files:
return jsonify({"IsSuccess" : isSuccess, "Message": "No file part"})
file = request.files['pictureFile'] # according to the name you append to formdata
if file: # and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(os.getcwd(), "static", "current_image.jpg"))
isSuccess = True
tasks = []
return jsonify({"IsSuccess" : isSuccess, "tasks": tasks})
return jsonify({"IsSuccess" : isSuccess, "Message": "Error occurs"})
Related
I am trying to build a Flask application to upload files to a GS bucket. I ran app.py on localhost, and when I try to submit the files, the server raises the 405 Method Not Allowed error. I searched everywhere, and nothing seems to help. Here is my code:
HTML Form:
<form action="/" method="POST" enctype="multipart/form-data">
<input
class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
id="multiple_files" type="file" multiple>
app.js:
document.getElementById("request").addEventListener("click", function (event) {
event.preventDefault();
const files = document.getElementById("multiple_files").files;
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("multiple_files", files[i]);
}
fetch("/", {
method: "POST",
headers: {
'Access-Control-Allow-Origin': '*'
},
body: formData
})
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
});
app.py
import os
import uuid
from flask import Flask, request, redirect, render_template
from google.cloud import storage
app = Flask(__name__)
# Set the bucket name and json authentication file values
bucket_name = "BUCKET_NAME"
auth_file = "AUTH_FILE"
# Initialize Google Cloud Storage client
client = storage.Client.from_service_account_json(auth_file)
bucket = client.get_bucket(bucket_name)
# Route for the file upload form
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
# Get the uploaded files
files = request.files.getlist("multiple_files")
# Upload each file to the Google Cloud Storage bucket
for file in files:
# Generate a unique file name
filename = str(uuid.uuid4()) + "-" + file.filename
blob = bucket.blob(filename)
blob.upload_from_file(file)
return redirect("/")
return render_template("index.html")
if __name__ == "__main__":
app.run(debug=True)
Can you please help me? I just started learning web development, and I cannot find any resource to help me fix this. Thanks!
I tried to change the "POST" to "PUT" but it also did not help.
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
session['link'] = request.form.get('link')
link = YouTube(session['link'])
return render_template('video.html', link=link)
return render_template('index.html')
#app.route('/download', methods=['GET', 'POST'])
def download():
if request.method == "POST":
link = YouTube(session['link'])
itag = request.form.get('itag')
video = link.streams.get_by_itag(itag)
filename = video.download()
return send_file(filename, as_attachment=True)
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
I want my youtube downloader code to display an error message when the user enters an invalid URL or if the video is unavailable. It is showing an internal server error if the user enters an invalid URL.
After changes:
#app.route('/', methods=['GET', 'POST'])
def index():
try:
if request.method == 'POST':
session['link'] = request.form.get('link')
link = YouTube(session['link'])
return render_template('video.html', link=link)
return render_template('index.html')
except:
return redirect(url_for('index'))
Now if the user enters the invalid URL the user gets redirected to the homepage but I want to Flash error message once the user gets redirected to the homepage.
Instead of you current API call, you can use the catch method with the new Fetch method in Javascript:
fetch('https://example.com/profile', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
The catch method triggers anytime when an error occurs. What you can do is specify different statements to output and check different crash criteria.
Sources:
Using Fetch
I'm working on an application that requires me to upload csv files to a FLASK server from an Angular frontend. i am having difficulties doing that. how can i connect the angular frontend to the backend flask server.
Here's my component.html
<div [hidden] = "submitted">
<form (ngSubmite) = "onSubmit()" action = "http://localhost:5000" method = "post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type = "submit" value="Upload">
</form>
Here's my component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-upload',
templateUrl: './upload.component.html',
styleUrls: ['./upload.component.css']
})
export class UploadComponent implements OnInit {
submitted = false;
constructor() { }
onSubmit(){
this.submitted = true;
}
ngOnInit() {
}
}
here's my flask server
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#app.route('/upload' , method = ['GET' ,'POST'])
def upload_File():
if request.method == 'POST':
#check if the psot request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
#if the user does not select file , browser alsos
#submite an empty part without filename
if file.filename == ' ':
flash('No selected file')
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
#return render_template('success.html', name = filename)
return redirect(request.url)
return 'File Uploaded'
Import HttpClientModule in your AppModule's imports.
Inject HttpClient in your component (move that logic into a service later) like this constructor(private readonly http: HttpClient) {}
And finally in your submit method you can do an http request this.http.post(url, body).subscribe()
I'm trying to forward a data-form request to another webservice but when I receive the new request in the other webservice, it contains the form data, but not the file data:
[+] Forward 1: ImmutableMultiDict([('content', <FileStorage: '0,1.txt' ('text/plain')>)])
[+] Forward 2: ImmutableMultiDict([('content', <FileStorage: 'content' (None)>)])
In the code, you can see that the index renders the form. You choose a file, and it sends it to the first webservice (forward1). In this webservice, it tries to send the request.form and the request.files to the second webservice (forward2). But not all the information arrives correctly.
What could be happening?
I have tried this, but this solutions doesn't work for me.
Forwarding multipart/form-data to different service (python, bottle, requests)
import requests
from flask import Flask, request, url_for
from werkzeug.datastructures import FileStorage
app = Flask(__name__)
#app.route('/')
def index(methods=['GET', 'POST']):
return """<html>
<form method="post" action="{}" enctype="multipart/form-data">
<input name="content" type="file" />
<input type="submit">
</form>
</html>""".format(url_for('forward1'))
#app.route('/fw1', methods=['GET', 'POST'])
def forward1():
if request.method == "POST":
payload = request.form
files = request.files
print("[+] Forward 1:", request.files)
response = requests.request(
"POST",
"http://XXX.XXX.XXX.XXX:5000/fw2",
data=payload,
files=files
)
return ""
#app.route('/fw2', methods=['GET', 'POST'])
def forward2():
if request.method == "POST":
print("[+] Forward 2:", request.files)
return ""
if __name__ == '__main__':
app.run(host='0.0.0.0', debug = True)
You can do it like below codes
response = requests.request(
"POST",
"http://XXX.XXX.XXX.XXX:5000/fw2",
data=payload,
files={k: (f.filename, f.stream, f.content_type, f.headers) for k, v in files.items()}
)
By using requests library it is very easy. The example shows multiple file uploads with same key and with other form data as well. The images are coming from a form with the key named 'images'
images = request.files.getlist('images')
files = []
for image in images:
files.append(("images", (image.filename, image.read(), image.content_type)))
r = requests.post(url=api_urls.insert_face_data_url, data={"apikey": apikey, "faceid": faceid},
files=files)
Assuming you are forward one file at a time Then create a file upload, then add it to the request as files.
file_payload = {file.name : (file.filename, file.stream, file.content_type, file.headers)}
response = requests.post(
url=url,
data=payload,
files=file_payload)
Solution:
response = requests.request(
"POST",
"http://XXX.XXX.XXX.XXX/fw2",
data=payload,
files={files["file"].name : (files["file"].filename, files["file"].file, files["file"].mimetype)}
)
I hope my question is clear enough.
So, I have a React form in component A. I want to pass the fields using an AJAX request to a Flask server, which processes the data received and updates the DOM in component B.
Tried looking up several other SO pages but none of them answered the question. And I'm super new to both AJAX and Flask, so that doesn't help either.
My current code looks like this:
Component A:
import React from "react";
class InputForm extends React.Component {
claimRef = React.createRef();
handleSubmit = event => {
event.preventDefault();
const claim = this.claimRef.current.value;
this.props.addClaim(claim);
$.ajax({
type: "POST",
url: "/test/",
data: claim
})
.done(function(data) {
// self.clearForm();
})
.fail(function(jqXhr) {
console.log("failed to register");
});
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Claim:
<textarea name="claim" ref={this.claimRef} placeholder="Claim" />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default InputForm;
Flask server:
#!/usr/bin/env python
import os
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def index():
return render_template('index.html')
#app.route('/test/', methods=['GET', 'POST'])
def test():
clicked = None
if request.method == "POST":
clicked = request
return render_template('test.html', clicked=clicked)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=os.environ.get('PORT', 3000), debug=True)
I've added a test.html file temporarily, which is supposed to simply print the data, but even localhost:3000/test just prints "None".
I get absolutely no errors in any part of the application, and I also get status 200 in the network tab of the webpage, which means that the data is being accepted.
How do I access the passed data and subsequently, print it in component B?
There is nothing wrong with your reactjs http post, however I would recommend you to use the fetch api. However, when you want to talk to the client from your server you have to use json.
Here is how you would make an http request to the server try this:
const data = this.claimRef.current.value;
fetch('/test/', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
})
.then(response => response.json())
.then(data => console.log(data));
Once you create make the http post to the server, this is how you retrieve the data from the server (flask)
#app.route('/test/', methods=['GET', 'POST'])
def test():
clicked = None
if request.method == "POST":
data = request.json
print(data) #json data from client (reactjs)
return jsonify(data='test')
# jsonify returns http response as json
Try it and see what you get! I hope this helps and good luck!
Be aware of CORS
fetch api
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch