File Upload using Dojo and Python

I was working on Azillia this past weekend and had trouble getting the File Uploader to work. Since I’m new to Python, debugging the errors were that much harder. However, I finally fixed it last night and everything seems to be working now. For those that are trying to do the same thing, here’s how I did it:


The HTML

<form action="/upload/" method="post" enctype="multipart/form-data" id="uploadForm">
    <input type="hidden" name="MAX_FILE_SIZE" value="10000000" />
    Choose a file to upload:<br />
    <input name="uploadFile" type="file" /><br />
    <input type="submit" id="uploadSubmit" value="Upload File" />
</form>

Pretty simple, really.  Just make sure you have an id on the form and the submit button.


The Javascript

<script type="text/javascript"
src="http://o.aolcdn.com/iamalpha/.resource/jssdk/dojo-0.2.2/dojo.js"></script>
<script type="text/javascript">
dojo.addOnLoad(function() {
    var handle = dojo.connect(dojo.byId('uploadSubmit'), 'onclick', function (evt) {
        // Prevent Default Behavior
        evt.preventDefault();

        dojo.xhrPost({
            url: "/upload/",

            load: function(response, ioArgs) {
                // do stuff

                return response;
            }, // end load

            error: function(response, ioArgs) {
                // do stuff

                return response;
            }, // end error

            form: 'uploadForm',
        }); // end xhrPost
    }); // end connect
}); // end addOnLoad
</script>

I’m adding a dojo connect to the “onclick” event of the submit button. Instead of submitting the form as usual, it will do an xhrPost to the specified URL. If the upload succeeds, I can do what I want within the “load” section of xhrPost (display a success message, hide the form, etc.). However, if it fails, the “error” section will be called and I can display a message or whatever else I want to do.

That’s all there is to it on the client side. On to the server side…


The Python

(r'^upload/$', 'common.views.upload'),

This gets added to my base urls.py, redirecting my POST call to the views file in my common directory.

from libs.Http import Http
import time

def upload(request):
    if request.method == 'POST':
        handle_file_upload(request.FILES['uploadedFile'])
	return HttpResponse('success')
    else:
        return HttpResponseBadRequest('error')

def handle_file_upload(f):
    fn = "".join(['uploads/', str(time.time()), '.jpg'])
    destination = open(fn, 'wb+')
    for chunk in f.chunks():
        destination.write(chunk)
    destination.close()

This will do the actual work of  the upload, basically taking the uploaded file and placing it in an uploads folder with the current timestamp as the filename.

NOTE:  This is a skimmed down version of the actual upload, not checking the filetype or anything of the sort. If you are going to use this, make sure you add those basic security checks into your code.

That’s all! Like I said, pretty easy stuff, but I got stuck on a few little things (I just didn’t know any better) and thought this might help someone else out. Let me know if you see any problems with this or have suggestions for ways to improve upon it!