HTML5 ajax file upload with flask

2013-06-26 ยท 397 words ยท 2 minute read

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