Implementing a dropbox service with the Blobstore API (part 3): Multiple upload support

Posted by Nick Johnson | Filed under app-engine, python, coding, blobstore, filehangar, cookbook

In the last part of this series, we demonstrated how to use plupload, a Javascript library with multiple backends for handling file uploads. The solution we demonstrated there only supported uploading a single file at a time, however, and required us to improvise our own progress indicators - far from optimal.

So now, the post you've all been waiting for, where we demonstrate how to do multiple file upload!

The basic trick is simple: Hook the event that's triggered before a file is uploaded, and update the URL to upload to when it's called. That way, ever uploaded file gets a new URL. Where do we get the URL from? We simply ask the server for one. Here's the Javascript for that:

uploader.bind('UploadFile', function(up, file) { $.ajax({ url: '/generate_upload_url', async: false, success: function(data) { up.settings.url = data; }, });

Straightforward, right? The only subtlety here is that we have to make the request an asynchronous one, so that the uploading doesn't start until we've updated the URL. Here's the server-side code that generates those URLs:

class GenerateUploadUrlHandler(BaseHandler): @util.login_required def get(self): self.response.headers['Content-Type'] = 'text/plain' self.response.out.write(blobstore.create_upload_url('/upload'))

Now that we're able to upload multiple files, we can do away with our duct-tape and fencing wire solution and use plupload's built in queue widget instead. Here's the updated HTML file, with the important changes highlighted:

<html> <head> <title>File Hangar: Upload file</title> <style type="text/css">@import url(/static/css/plupload.queue.css);</style> <script type="text/javascript" src="http://www.google.com/jsapi"></script> <script type="text/javascript"> google.load("jquery", "1.4"); </script> <script type="text/javascript" src="/static/plupload/gears_init.js"></script> <script type="text/javascript" src="/static/plupload/plupload.full.min.js"></script> <script type="text/javascript" src="/static/plupload/jquery.plupload.queue.min.js"></script> <script type="text/javascript"> $(function() { uploader = $("#uploader").pluploadQueue({ runtimes: 'flash,html5,gears,html4', use_query_string: false, multipart: true, flash_swf_url: '/static/plupload/plupload.flash.swf', filters: [{title:'dmgs', extensions:'dmg'}], }).pluploadQueue(); uploader.bind('UploadFile', function(up, file) { $.ajax({ url: '/generate_upload_url', async: false, success: function(data) { up.settings.url = data; }, }); }); }); </script> </head> <body> <p style="float: right"><a href="{{logout_url}}">Log Out</a></p> <h1>Upload a file to App Engine File Hangar</h1> <form> <div id="uploader"> </div> </form> </body> </html>

That's all there is to it! Your users can now upload multiple files seamlessly, using a sophisticated widget with progress indication and queueing. As always, the complete code for this example is available here. In the next post in the series, we'll demonstrate how to start building a real, coherent dropbox service from the parts we've assembled so far. Got a feature you'd like to see in such a service? Speak up!

Disqus