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

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

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

How to do POST using requests module with Flask server?

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.

Flask redirect doesn't work after upload

I basically want to go to a different page after the upload. What happens here is that the file is uploaded very quickly and saved on the server, but after that the client(my browser) is in the Waiting stage for a minute each time and doesn't even redirect after the wait. If I remove it, I don't get any response back as expected and everything happens within milliseconds.
#blah.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST' and 'file' in request.files:
file = request.files['file']
if file:
filename = secure_filename(file.filename)
file.save(os.path.join('./tmp/uploads', filename))
print '%s file saved' % filename
return redirect(url_for("blah.list_uploads"))
return render_template('blah/upload.html')
Edit: Not sure if it will help to say that I'm using DropzoneJS. I think by default it uses Ajax. Maybe it has something to with that?
Update: Now you can use Flask-Dropzone, a Flask extension that integrates Dropzone.js with Flask. For this issue, you can set DROPZONE_REDIRECT_VIEW to the view you want to redirect when uploading complete.
Dropzone control the upload process, so you have to use Dropzone to redirect (make sure jQuery was loaded).
Create an event listener, it will redirect page when all files in the queue finish uploading:
<form action="{{ url_for('upload') }}" class="dropzone" id="my-dropzone" method="POST" enctype="multipart/form-data">
</form>
<script src="{{ url_for('static', filename='js/dropzone.js') }}"></script>
<script src="{{ url_for('static', filename='js/jquery.js') }}"></script>
<script>
Dropzone.autoDiscover = false;
$(function() {
var myDropzone = new Dropzone("#my-dropzone");
myDropzone.on("queuecomplete", function(file) {
// Called when all files in the queue finish uploading.
window.location = "{{ url_for('upload') }}";
});
})
</script>
Handle the redirect in view function:
import os
from flask import Flask, render_template, request
app = Flask(__name__)
app.config['UPLOADED_PATH'] = os.getcwd() + '/upload'
#app.route('/')
def index():
# render upload page
return render_template('index.html')
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
for f in request.files.getlist('file'):
f.save(os.path.join(app.config['UPLOADED_PATH'], f.filename))
return redirect(url_for('where to redirect'))

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