I want to make a multiple file-upload form.I use jQuery File Uploader. My server-side code:
@app.route("/new/photogallery",methods=["POST"])
def newPhotoGallery():
print request.files
I tried two things:
Submit form normally:
When i submit my form normally,it prints:
ImmutableMultiDict([('post_photo_gallery', FileStorage: u'' ('application/octet-stream'))])
Submit form using AJAX:
When i submit my form using AJAX,it prints:
ImmutableMultiDict([])
My first question is: Why is there a difference between AJAX request and normal request.
My second question is: How can i handle this application/octet-stream
request in Flask/Python
My third question is: Is this a good way to use application/octet-stream
?
By the way i do not know much about application/octet-stream
.Thank you very much.
The application/octet-stream MIME type is used for unknown binary files. It preserves the file contents, but requires the receiver to determine file type, for example, from the filename extension. The Internet media type for an arbitrary byte stream is application/octet-stream .
Handling file upload in Flask is very easy. It needs an HTML form with its enctype attribute set to 'multipart/form-data', posting the file to a URL. The URL handler fetches file from request. files[] object and saves it to the desired location.
APPLICATION/OCTET-STREAM stands for binary data. It may be more precise by specifing the actual filetype. For images it coud be image/png . If the browser knows the exact filetype it may show the file directly.
I was unable to get a request working using application/octet-stream
type posts, but have used multipart/form-data
type forms in the past to upload images using flask.
I have extended what I have done in the past to support multiple upload files and this has worked leveraging werkzeug's FileStorage
objects.
The key here is setting up a post based route that is looking for a request element from a form. This should allow you to POST to the route either via a standard form or an AJAX call.
Below is a simplified example that is using a form:
Template for the view:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
</head>
<body>
{% if err %}
<h4>{{ err }}</h4>
{% endif %}
<form action="/" method=POST enctype=multipart/form-data id="fileupload">
<input type="file" name="files" data-url="/" multiple>
<input type=submit value=Post>
</form>
{% if files %}
{% for file in files %}
<p>Uploaded: <b>{{ file }}</b> </p>
{% endfor %}
{% endif %}
</body>
</html>
Flask App
from flask import Flask, request, render_template
from werkzeug import secure_filename, FileStorage
import os
# Flask functions
app = Flask(__name__)
app.config.from_object(__name__)
DEBUG = True
# add this so that flask doesn't swallow error messages
app.config['PROPAGATE_EXCEPTIONS'] = True
@app.route('/', methods=['GET', 'POST'])
def uploader():
if request.method =='POST' and request.files.getlist('files'):
up_file_list = []
# Iterate the through a list of files from the form input field
for a_file in request.files.getlist('files'):
if a_file.filename:
# Validate that what we have been supplied with is infact a file
if not isinstance(a_file, FileStorage):
raise TypeError("storage must be a werkzeug.FileStorage")
# Sanitise the filename
a_file_name = secure_filename(a_file.filename)
# Build target
a_file_target = os.path.join('/tmp/', a_file_name)
# Save file
a_file.save(a_file_target)
up_file_list.append(a_file_name)
# Return template
if up_file_list:
return render_template('uploader.html', err=None, files=up_file_list)
else:
return render_template('uploader.html', err='No Files Uploaded', files=None)
else:
return render_template('uploader.html', err=None, files=None)
# application execution
if __name__ == '__main__':
app.run()
Regardless of the the data encoding, you should be able to get the raw data with request.data
.
In the case of application/octet-stream
, you can just write request.data
to a binary file.
An example handler for various data types:
from flask import json
@app.route('/messages', methods = ['POST'])
def api_message():
if request.headers['Content-Type'] == 'text/plain':
return "Text Message: " + request.data
elif request.headers['Content-Type'] == 'application/json':
return "JSON Message: " + json.dumps(request.json)
elif request.headers['Content-Type'] == 'application/octet-stream':
with open('/tmp/binary', 'wb') as f:
f.write(request.data)
f.close()
return "Binary message written!"
else:
return "415 Unsupported Media Type ;)"
The typical scenario of handling form data is already documented here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With