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()
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.
I have an MWE of the problem in the following html template:
<block body>
<h2> Test Report </h2>
<form method="post">
<input type="submit" value="Generate Report">
</form>
</block body>
With the associated flask blueprint:
#bp.route('/reports2', methods=('GET', 'POST'))
#login_required
def reports2():
if request.method == 'POST':
from io import BytesIO
byte_obj = BytesIO()
byte_obj.write(b'Hello, I am a test file')
return send_file(byte_obj, as_attachment=True, download_name='test-downloaded-report.txt', mimetype='text/plain')
return render_template('report/reports2.html')
The result is bewildering. There's no file created in my downloads directory called 'test-downloaded-report.txt'. Instead, it downloads reports2.html!
I also originally just had send_file without being returned, instead returning a redirect to reports2.html so that the form would reset. Nothing happened there, so I assume the return is necessary for anything to happen, but as an aside I also don't see how I should send a file for download and redirect to a different page.
Any idea why that file is getting sent, instead of the file I created?
The file is not served as expected because the pointer is at the end of the stream. By putting the pointer at the beginning, the data can be read completely and should download as expected.
#bp.route('/reports2', methods=('GET', 'POST'))
#login_required
def reports2():
if request.method == 'POST':
from io import BytesIO
byte_obj = BytesIO()
byte_obj.write(b'Hello, I am a test file')
byte_obj.seek(0)
return send_file(
byte_obj,
as_attachment=True,
download_name='test-downloaded-report.txt',
mimetype='text/plain'
)
return render_template('report/reports2.html')
Forwarding after downloading or resetting the form is a little more complicated. As you correctly noticed, send_file is a response from the server. It cannot be used in conjunction with a redirect.
However, the following suggestion shows you how to use JavaScript to send the form, download the file and then reset the form. With a little adjustment you should also be able to forward to another location.
from flask import (
Flask,
render_template,
request,
send_file
)
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
from io import BytesIO
byte_obj = BytesIO()
byte_obj.write(b'Hello, I am a test file')
byte_obj.seek(0)
return send_file(
byte_obj,
as_attachment=True,
download_name='test-downloaded-report.txt',
mimetype='text/plain'
)
return render_template('index.html')
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Generate Report</title>
</head>
<body>
<h2>Test Report</h2>
<form name="my-form" action="{{ url_for('index') }}" method="post">
<input type="submit" value="Generate Report">
</form>
<script type="text/javascript">
(function() {
const download = (url, form, callback) => {
fetch(url, {
method: 'post',
body: new FormData(form)
}).then(resp => {
resp.ok && resp.blob().then(blob => {
callback(blob, resp.headers);
});
});
};
const save = (data, filename) => {
const elem = document.createElement('a');
elem.href = URL.createObjectURL(data);
elem.download = filename;
elem.click();
};
const form = document.querySelector('form[name="my-form"]');
form.addEventListener('submit', evt => {
evt.preventDefault();
download(evt.target.action, evt.target, (data, headers) => {
// Extract the filename from the "Content-Disposition" header.
const disposition = headers.get('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
const filename = matches[1].replace(/['"]/g, '');
save(data, filename);
}
}
});
// Reset the form or redirect to another location.
evt.target.reset();
})
})();
</script>
</body>
</html>
I'm creating a react app that utilizes a flask backend that serves as a REST API. Unfortunately, I've been having issues with the fetch command, in that it always seems to say fetch failed loading: [method]. The backend seems to handle the request fine.
127.0.0.1 - - [20/Jul/2021 21:10:35] "GET /api/login HTTP/1.1" 200 -
I've tried the request in postman and it works fine. I'm using a proxy for HTTP://localhost:5000 in my package.json so I don't think this is a CORS problem, and I've also tried using flask_cors to no avail. Has anyone experienced something like this before with fetch API? I'm fairly new to javascript so there may be something I'm not noticing.
Thanks.
Users.py (blueprint)
from . import bp
from flask import jsonify, request, make_response
#bp.route('/login', methods=['GET'])
def login():
return jsonify({'status': 'success'})
init.py (blueprint)
from flask import Blueprint
bp = Blueprint('rest', __name__)
from . import users
init.py (app)
def create_app():
from .config import Config
app = Flask(__name__)
app.config.from_object(Config)
mail = Mail(app)
from .models import db, Visitor, User
db.init_app(app)
migrate = Migrate(app, db)
#app.shell_context_processor
def make_shell_context():
return {"config": Config, "db": db, "Visitor": Visitor, "User": User}
#jwt.init_app(app)
app.register_blueprint(api_bp, url_prefix='/api')
return app
Request (from react button event handler)
export default function LoginUser(props) {
const [user, setUser] = useState({})
function handleChange(e) {
const { name, value } = e.target
switch (name) {
case 'email':
setUser({ ...user, email: value });
break;
case 'password':
setUser({ ...user, password: value });
break;
default:
break;
}
}
function handleSubmit(e) {
fetch('/api/login').then(res => res.json()).then().catch(error => console.log('error'))
}
return (
<Form>
<Form.Group className="mb-3" controlId="LoginEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email"
placeholder="Enter email"
name="email"
onBlur={handleChange} />
</Form.Group>
<Form.Group className="mb-3" controlId="LoginPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
name="password"
onBlur={handleChange} />
</Form.Group>
<Button variant="primary" type="submit" onClick={handleSubmit}>
Submit
</Button>
</Form>
)
}
Browser error (Brave)
handleSubmit # main.chunk.js:781
callCallback # vendors~main.chunk.js:24274
invokeGuardedCallbackDev # vendors~main.chunk.js:24323
invokeGuardedCallback # vendors~main.chunk.js:24383
invokeGuardedCallbackAndCatchFirstError # vendors~main.chunk.js:24398
executeDispatch # vendors~main.chunk.js:28633
processDispatchQueueItemsInOrder # vendors~main.chunk.js:28665
processDispatchQueue # vendors~main.chunk.js:28678
dispatchEventsForPlugins # vendors~main.chunk.js:28689
(anonymous) # vendors~main.chunk.js:28900
batchedEventUpdates$1 # vendors~main.chunk.js:42585
batchedEventUpdates # vendors~main.chunk.js:24072
dispatchEventForPluginEventSystem # vendors~main.chunk.js:28899
attemptToDispatchEvent # vendors~main.chunk.js:26382
dispatchEvent # vendors~main.chunk.js:26300
unstable_runWithPriority # vendors~main.chunk.js:56804
runWithPriority$1 # vendors~main.chunk.js:31680
discreteUpdates$1 # vendors~main.chunk.js:42602
discreteUpdates # vendors~main.chunk.js:24084
dispatchDiscreteEvent # vendors~main.chunk.js:26266
Try to change
fetch('/api/login').then(res => console.log(res)).catch(error => console.log('error')) to fetch('/api/login').then(res => res.json()).then(result => console.log(result)).catch(error => console.log('error')).
Because using fetch, your 'res' is just an HTTP response, not the actual JSON. So you need res.json() to get the JSON body.
Edit version
Change <Button variant="primary" type="submit" onClick={handleSubmit}> to <Button variant="primary" type="submit" onClick={(e)=>handleSubmit(e)}>. Also add e.preventDefault() in the handleSubmit function to prevent the page from refreshing.
Note: You should pass your user in api login
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
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"})