Skip to main content

AJAX File Upload with Web2py

It was not that long, since I experienced a problem while trying to upload a file using an ajax  trapped form. I thought, it must be me doing something wrong. I was using web2py to embed another page into a page via ajax. That is better known to web2py folk as LOADing a component.

It's just happened that one of such component contains a file upload form. It was my first time using LOAD function provided by web2py. Basically it make use of jQuery to load the page via ajax into a target div and traps input of any form in that page, so that page doesn't reload. Oh, I forgot to say that web2py is bundled with jQuery.

It's always boring and tedious to understand a problem without experiencing it. So, Let's play with an example, (PS: I"m using web2py a full stack python framework, but you can use any language at server side and this problem will be there because, it's a problem with ajax)

My model which defines table like this,

In RDBMS world, it column 'file' of table 'image' will transformed to a type of CHAR(or VARCHAR) and column must not be empty (notnull)
Web2py can enforce this at many levels.
notnull = True is enforced by database
required = True is enforced by DAL (database abstraction layer) of web2py
requires = IS_NOT_EMPTY() is enforced by SQLFORM.
You are free to use any of them and it's up to you to use all of them or only one of them. (we give choice :-) )

Now, the index function which maps a url and renders output

As you see web2py automates almost everything (yes, you can customize everything, and do it manually, if you want). This code generate an upload form as per database table IMAGE. automatically upload file into database, and if there's errors shows them to the user. After successful upload page is redirected to /upload/default/index.html. Wow, Magick! :-)

Now go to myform.html > You will be greeted with a file upload form and it just work.

OK, now we decided to embed myform.html into another page(say index.html).

For that we wrote {{=LOAD(URL(c='default', f='myform.load'))}} in index.html and it got transformed to:

for non-web2py folks, URL function generate url, and here .load is served with a content type of text/html. By using .load extension page is rendered without any template we set up for regular html display. The url /example/default/myform.load is of course a relative url, it get interpreted as Here 'example' is application, 'default' is controller and myform is a function. ie., will map to a function called myform() in a file in an application called example and rendered based on extension(.load, .html, .json, .xml etc).

I can't figure out what's going on. It always showed an error message stating that file is empty.
And I fire up my browser's developer plugins and it become clear that file is not being sent to server via ajax. Yes, it's because ajax can't sent files (read XMLHTTP object).

There are two remedies for this (as far as I can think of)
1) use an iframe to load component. Since there is no AJAX there, it'll work.
this is as simple as writing {{=IFRAME(_src=URL(c='default', f='myform.load'))}} in your view. (here index.html).

But, I hate iframe you may say (whether you say it or not, I'll). I learned a lesson in past that users care about functionality and not a bit about whether we use this or that and follows standard. So, I'm ready to break some if that cause better usability. (So I used iframe). Don't be disappointed, I have another option for you folks,

2) Use one of many ajax file upload plugins. I am going to show a solution based on uploadify library. It uses swfupload. and jQuery. So, if you really want to avoid iframe and burden users by making them download few more dependencies download uploadify library and extarct it into your server. (That said, this library is great if you want to implement multi-file upload). By using uploadify, you are going to do DB insert yourself. (if that's OK go ahead). Extract uploadify download into a folder called 'uploadify' under static directory.

change myform function to:

However, I tried it without embedding into another page, but it'll work even if it's embedded.
There are many different plugins available to do the same, each differs in their approach(like submitting form to an embed iframe.
So take your time to find them and go through them. (So server side code may change depending on your library of choice).
Please look these libraries:

  1. valums ajax upload
  2. jQuery Form plugin

Happy experimentations  :)


  1. Hi, if I set "auto" option = false, have this error:
    AttributeError: 'NoneType' object has no attribute 'file'. How fix it?

  2. It had been months since I wrote this.

    A possible cause for error might be erroneous ajax calls that the library is making.
    Can you open firebug and give the failed request url&params for auto=false, and succes request url&params for good scenario.

    then I can better help you.


Post a Comment

Popular posts from this blog

Rich Internet Application & GWT : Angel of Java Programmers

We all are hearing the buzz about Rich Internet Applications (RIA) about a year or so. But, what the heck is that beast? You may ask. For the user's perspective, it's the desktop like experience delivered over web. Yes, you feel like you are using a real desktop application (well, at least sort of). The richness of desktop controls is transferred to web.

How RIA is build? Arise another question. These all started with that amazing kid called AJAX (Asynchronous JavaScript And XML). Then more and more tools become available, like Java FX, Adobe Air, Adobe Flex (and Adobe Flash), Microsoft Silverlight. But these tools, though it gives rapid and organized web application development, required some kind of plug-ins to be installed on your browser. There is the importance of AJAX based RIAs, because JavaScript is enabled in almost all browsers in use today.

However, It's not a fool proof solution, because there are people who switch off JavaScript for some reason, like me ;-).  Bu…

Set difference: Data provided from two big files with one number at a line

Today, I had to find out difference between two huge lists of numbers.
Numbers are 17 digits long and list are of around 1 lac.

PS: I'm documenting both versions here for my future reference.

I used python, because diff doesn't felt good for me. because it will print both ins and outs of both files. Also, I ruled out diff's possibility, because I didn't felt it will work at that time.

Later, at home: I give diff a try.
Yes, it's not that beautiful as in python. I'd cut and sed a bit.
But still, it's a "one liner" and I like 'em a lot.