Making web uploads less painfull ๐
For one of my current Flask projects i want to have a nice looking and easy to use file upload form.
That means no input type="file"
form field where i have to select each file and the upload it on at a time.
I came across
this nice tutorial
for a HTML5/jquery file uploader, but the backend is written in PHP.
So I decided to try to get this working with Flask and it was easier as I supposed :-)
The server side ๐
This is the server side code:
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4import os
5from datetime import datetime
6from flask import Flask, render_template, jsonify, redirect, url_for, request
7
8app = Flask(__name__)
9app.config.from_object(__name__)
10app.config['UPLOAD_FOLDER'] = 'uploads'
11
12ALLOWED_EXTENSIONS = ['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']
13
14@app.route("/")
15def index():
16 return render_template("index.html")
17
18@app.route('/upload', methods=['POST'])
19def upload():
20 if request.method == 'POST':
21 file = request.files['file']
22 if file and allowed_file(file.filename):
23 now = datetime.now()
24 filename = os.path.join(app.config['UPLOAD_FOLDER'], "%s.%s" % (now.strftime("%Y-%m-%d-%H-%M-%S-%f"), file.filename.rsplit('.', 1)[1]))
25 file.save(filename)
26 return jsonify({"success":True})
27
28def allowed_file(filename):
29 return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
30
31if __name__ == "__main__":
32 app.run(debug=True)
The code is very simple, the route / displays the template with the dropzone for the files. The /upload route takes the sent POST data (the files).
The client side ๐
The index template:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8" />
5 <title>HTML5 / jQuery</title>
6 <link rel="stylesheet" href="static/css/styles.css" />
7 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
8 <script type="text/javascript" src="static/js/jquery.filedrop.js"></script>
9 <script type="text/javascript" src="static/js/upload.js"></script>
10 </head>
11 <body>
12 <div id="dropbox">
13 <span class="message">Drop images here to upload.</span>
14 </div>
15 </body>
16</html>
And the important part of the upload.js:
1dropbox.filedrop({
2 paramname: 'file',
3 maxfiles: 10,
4 maxfilesize: 5,
5 url: '/upload',
6 uploadFinished:function(i,file,response){
7 $.data(file).addClass('done');
8 }
9})
It’s important that paramname: 'file'
in upload.js is equal to the key in app.py file = request.files['file']
. Otherwise you will get a Error 400 Bad Request
.
Also, the url
parameter in upload.js has to be equal to the defined route in app.py.
When you drag&drop files to the dropzone, they will be saved in /uploads. I decided to replace the filename by the upload date, because otherwise the widespread IMG_XXX.JPG filenames possibly overwrite a already uploaded file.
And that’s it :-)
You can find a working example on my GitHub account