How to do POST using requests module with Flask server? - python

I am having trouble uploading a file to my Flask server using the Requests module for Python.
import os
from flask import Flask, request, redirect, url_for
from werkzeug import secure_filename
UPLOAD_FOLDER = '/Upload/'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#app.route("/", methods=['GET', 'POST'])
def index():
if request.method == 'POST':
file = request.files['file']
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('index'))
return """
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
<p>%s</p>
""" % "<br>".join(os.listdir(app.config['UPLOAD_FOLDER'],))
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
I am able to upload a file via web page, but I wanted to upload file with the requests module like this:
import requests
r = requests.post('http://127.0.0.1:5000', files={'random.txt': open('random.txt', 'rb')})
It keeps returning 400 and saying that "The browser (or proxy) sent a request that this server could not understand"
I feel like I am missing something simple, but I cannot figure it out.

Because you have <input> with name=file so you need
files={'file': ('random.txt', open('random.txt', 'rb'))}
Examples in requests doc: POST a Multipart-Encoded File

You upload the file as the random.txt field:
files={'random.txt': open('random.txt', 'rb')}
# ^^^^^^^^^^^^ this is the field name
but look for a field named file instead:
file = request.files['file']
# ^^^^^^ the field name
Make those two match; using file for the files dictionary, for example:
files={'file': open('random.txt', 'rb')}
Note that requests will automatically detect the filename for that open fileobject and include it in the part headers.

Related

How to prevent uploaded files from having the same name Flask Python

I am trying to build a website in python using flask that takes file uploads and saves them to a folder (called uploads). However, when two files with the same name are uploaded, the first one is overwritten by the last one. How can I prevent this in a way that means that I don't lose any files? Would adding a timestamp to the filename help or would there still be an issue if two files are uploaded at the same time?
Thanks!
Filesystem
FlaskProject:
├───static
├───templates
├───uploads
└───app.py
Html
{%extends "base.html" %}
{%block content%}
<p>
<h2>Upload Below!</h2>
<div></div>
<form action = "http://localhost:5000/upload_complete" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit"/>
</form>
{% endblock %}
Python
from flask import Flask, redirect, url_for, render_template, request
from werkzeug.utils import secure_filename
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = "D:/Me/FlaskProject/uploads"
#app.route('/upload')
def upload():
return render_template("upload.html", page="Upload Images")
#app.route('/upload_complete', methods = ['GET', 'POST'])
def upload_complete():
if request.method == 'POST':
f = request.files['file']
f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))
return redirect(url_for('upload_complete'))
return render_template("upload_complete.html", page="Upload Complete")
if __name__ == '__main__':
app.debug = True
app.run()
app.run(debug = True)
(upload_complete.html is just a thank you screen)
You can generate an uuid and update the filename with it.
You can generate uuid like this,
import uuid
... your code ..
hash_value = uuid.uuid4().hex
f.save(os.path.join(app.config['UPLOAD_FOLDER'], hash_value + secure_filename(f.filename)))

Upload to Minio directly from Flask service

I want to store a file from a Flask service to a Minio Bucket without storing it in a directory first. What I can do so far is have the user upload a file using a Flask service, store it in a directory, and then use the put_object function from Minio to upload it.
Is something like that possible?
Below you can see the upload_file flask method and the upload_object method that utilizes the put_object function from Minio:
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', '7z', 'iso'}
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET','POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return 'No file found'
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
return 'msg error'
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save('uploads/'+filename)
print(file.filename)
# upload file to minio service
upload_object(name=str(file.filename))
return 'object stored in bucket'
return '''
<!doctype html>
<title>Upload IPS File</title>
<h1>Upload IPS File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
'''
And the upload_object():
def upload_object(name):
try:
path = 'uploads/'+str(name)
print(path)
file_data = open(path, 'rb')
print(file_data)
file_stat = os.stat('uploads/'+str(name))
print(minioClient.put_object('miniotestbucket', str(name), file_data, file_stat.st_size))
except ResponseError as e:
print(e)
except FileNotFoundError as e:
print(e)
I already checked this Question but I did not quite understand what was needed to do.
It should absolutely be possible since you just read the file content after saving it. This post tells a bit more about FileStorage. Since FileStorage extends stream you have many of the same features while reading the file from the request as when reading it from a file on disk. Since you cannot stat the file I used another way to tell the size of the file found here.
You can try something like this:
#app.route("/", methods=["GET", "POST"])
def upload_file():
if request.method == "POST":
uploaded_file = request.files["file"]
if uploaded_file:
bucket_name = "miniotestbucket"
size = os.fstat(uploaded_file.fileno()).st_size
minioClient.put_object(
bucket_name, uploaded_file.filename, uploaded_file, size
)
return "object stored in bucket"
return """
<!doctype html>
<title>Upload IPS File</title>
<h1>Upload IPS File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
"""
I don't have access to a Minio bucket but I did some testing by uploading a YAML file and reading the contents with yaml.load() which worked just fine.

How can I upload and then download a file through flask?

I prepared a script in which user can upload a file as an input file (text.dat) and then after importing it into a function (compute), another file as an output (server.log) can be downloaded by user.
But the script does not work properly - it requests for the input file but can not be downloaded at the end.
import os
from flask import Flask, request, render_template, url_for, redirect, send_file,
from compute import compute
app = Flask(__name__)
#app.route("/")
def fileFrontPage():
return render_template('fileform.html')
#app.route("/handleUpload", methods=['GET','POST'])
def handleFileUpload():
if 'photo' in request.files:
photo = request.files['photo']
if photo.filename != '':
photo.save(os.path.join('/home/Documents/web', photo.filename))
return redirect(url_for('fileFrontPage'))
#app.route('/download', methods = ['GET', 'POST'])
def tes():
with open("/home/Documents/web/download/server.log", "w") as fd, open('/home/Documents/web/text.dat', 'r') as out:
path = "server.log"
for i in out:
s = compute(float(i))
fd.write("{} \n".format(s))
return send_file('/home/Documents/web/download/server.log',as_attachment=True, attachment_filename='server.log')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
My html file as follows:
<html>
<head>
<title>Simple file upload using Python Flask</title>
</head>
<body>
<form action="/handleUpload" method="post" enctype="multipart/form-data">
Choose the file: <input type="file" name="photo"/><BR>
<input type="submit" value="Upload"/>
</form>
</body>
</html>
Change the route of tes() to something that doesn't conflict with fileFrontPage(), e.g. #app.route('/download')

Python how to upload file to webservice using Flask module?

I'm following this tutorial on how to set up file uploading webservice using Flask. Below is a snipped of my code. I can see that the def upload_file(): gets the correct filename and allows it through, however, the line that actually saves the file does not get executed and I receive "Internal server error (500)" response. It seems that the issue is with actually storing files on disk.
What else do I need to do to set up my web service to save received files using Flask?
UPDATED - the code below works now
from flask import Flask
from flask import Response, jsonify, request, redirect, url_for
#persistent storage in dictionary
import shelve
#printing ip of host
import socket
#file uploading
import os
from werkzeug.utils import secure_filename
#serving files that were uploaded
from flask import send_from_directory
#mac-specific relative path to the script's location
UPLOAD_FOLDER = './audio'
ALLOWED_EXTENSIONS = set(['txt', 'm4a', 'mp4'])
#configuration
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
print 'upload file'
try:
os.stat(app.config['UPLOAD_FOLDER'])
except:
os.mkdir(app.config['UPLOAD_FOLDER'])
if request.method == 'POST':
file = request.files['file']
print 'filename: ' + file.filename
if file and allowed_file(file.filename):
print 'allowing file'
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('uploaded_file',filename=filename))
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
#app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
if __name__ == '__main__':
print(socket.gethostbyname(socket.gethostname()))
app.run(host='0.0.0.0')

Make drag and drop uploader in flask

I'm trying to make upload site that takes request and stores the files in 'static' folder in flask. I always get bad request when I try sending "POST" request on in.The only reason that I need it is to test my drag and drop javascript uploader. Can someone point me in the right direction?
import os
from flask import Flask, request, redirect, url_for
from werkzeug import secure_filename
UPLOAD_FOLDER = 'static'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['xhr2upload'] # [0]
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('uploaded_file',
filename=filename))
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
if __name__ == '__main__':
app.run()
This is a common problem to have with Flask early on - when you attempt to access request.args, request.form, request.values and request.files they will throw a KeyError if the key does not exist in them - just as an ordinary dictionary would in Python (try {}["test"] in any Python interpreter). Flask adds a bit of sugar to the request dictionaries - its KeyError is actually a subclass of HTTPException that raises a 400 Bad Request if it is not caught. (See this part of the quickstart documentation)
The line that is causing this issue is request.files['xhr2upload']. You do not include any JavaScript on the page and the only <input type="file"> you have on the page has the name of "file", not "xhr2upload". Either change request.files['xhr2upload'] to request.files['file'] or load an ajax uploader into your page and have it post your files using the xhr2upload name.
If you have a form that may have a field and you want to check if a field is defined without raising a KeyError then you can use the .get method:
request.form["not_here"] # KeyError -> 400 Bad Request
request.form.get("might_be_here") # Value if provided, else None
you must add "multiple" to file input tag, like so:
<input type="file" name=file multiple>
and made an for bucle instead "file" on flask backend
files = ...
for file in files
file.save(os.path.join...

Categories