In this blog post I'll show you how to upload files with the Flask Microframework. The code from this example is taken from my MinCloud open source project. Maybe this is not the ready to copy-paste-example, but I hope I explain all the stuff that goes on. If you have any questions, just leave a comment below.
Code
First my upload code which is available here. (MIT License)
@myapp.route("/api/upload", methods=['GET', 'POST'])
@flask_login.login_required
def _upload():
if request.method == 'POST':
file = request.files['files[]']
# get filename and folders
file_name = secure_filename(file.filename)
directory = str(unique_id())
upload_folder = myapp.config['UPLOAD_FOLDER']
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
save_dir = os.path.join(upload_folder, directory)
if not os.path.exists(save_dir):
os.makedirs(save_dir)
cmpl_path = os.path.join(save_dir, file_name)
file.save(cmpl_path)
size = os.stat(cmpl_path).st_size
# create our file from the model and add it to the database
dbfile = File(file_name, directory, size, file.mimetype)
g.user.uploads.append(dbfile)
db.session().add(dbfile)
db.session().commit()
if "image" in dbfile.mimetype:
get_thumbnail(cmpl_path, "100")
thumbnail_url = request.host_url + 'thumbs/' + directory
else:
thumbnail_url = ""
url = request.host_url + 'uploads/' + directory
delete_url = url
delete_type = "DELETE"
file = {"name": file_name, "url": url, "thumbnailUrl": thumbnail_url, "deleteUrl": delete_url,
"deleteType": delete_type}
return jsonify(files=[file])
else:
return jsonify(files=[{"name": file_name, "error": responds['FILETYPE_NOT_ALLOWED']}])
Step-by-Step
@myapp.route("/api/upload", methods=['GET', 'POST'])
@flask_login.login_required
def _upload():
if request.method == 'POST':
file = request.files['files[]']
If you look at the head of my upload function you'll see I require an login and the function is routed from /api/upload
. So if you send an HTTP-GET
or an HTTP-POST
to the url this function is called.
As I use the jQuery-FileUpload from Blueimp. I access the file through request.files['files[]']
and then process it further.
# get filename and folders
file_name = secure_filename(file.filename)
directory = str(unique_id())
upload_folder = myapp.config['UPLOAD_FOLDER']
if file.filename == '':
return redirect(request.url)
Then I'll get the filename it's important to use a secure filename which checks for filenames that could compromise your server. Such as ../../../etc/passwd
. For more examples visit the werkzeug page.
Upload Folder
The upload folder I'm currently setting in my config file and get it with myapp.config['UPLOAD_FOLDER']
.
Then if the filename is just nothing I return a redirect to the request.url
.
if file and allowed_file(file.filename):
save_dir = os.path.join(upload_folder, directory)
if not os.path.exists(save_dir):
os.makedirs(save_dir)
cmpl_path = os.path.join(save_dir, file_name)
file.save(cmpl_path)
size = os.stat(cmpl_path).st_size
I check with my allowed_file(file.filename)
function if the extension of the file is in my allowed list of extension. I'm planning to do this with a database setting in future updates.
As I want to save some metadata in my database I'll get the size from the file.
Also I set up my file saving folders.
/opt/mincloud/uploads/
├── directory/
├── uploadedfile.extensions
So I'll save a uploaded file in my upload folder in an created folder with an unique id. This unique id is also saved in my database.
# create our file from the model and add it to the database
dbfile = File(file_name, directory, size, file.mimetype)
g.user.uploads.append(dbfile)
db.session().add(dbfile)
db.session().commit()
if "image" in dbfile.mimetype:
get_thumbnail(cmpl_path, "100")
thumbnail_url = request.host_url + 'thumbs/' + directory
else:
thumbnail_url = ""
In this section I'll create an file for my database, and append it to the users uploads.
I use a thumbnail library and do some thumbnail stuff.
url = request.host_url + 'uploads/' + directory
delete_url = url
delete_type = "DELETE"
file = {"name": file_name, "url": url, "thumbnailUrl": thumbnail_url, "deleteUrl": delete_url,
"deleteType": delete_type}
return jsonify(files=[file])
else:
return jsonify(files=[{"name": file_name, "error": responds['FILETYPE_NOT_ALLOWED']}])
And at last I'll create the download url and the return json which complies with the jQuery-File Upload Library.
If you press this Button it will Load Disqus-Comments. More on Disqus Privacy: Link