Wednesday, June 21, 2006

AGAD!! (Tutorial-ish sort of post)

Please note this blog has now moved Here.

Asynchronous Google (Web Toolkit) and Django

Personally, I think that the acronymn is way more fun to say than "Ajax". Picture this, you're sneaking up behind someone at a party... you wait until the perfect moment when the music has just paused slightly between songs and you yell one of two things, you yell "AJAX!" or "AGAD!" Also, it should be noted, that the person you chose to sneak up behind has been horribly disfigured by a childhood accident involving large quantities of a brand-name cleaner. NOW, which are you going to yell? At this point, the superiority of AGAD should be evident, but just in case not, I will proceed to actually talk about it.

The Google Web Toolkit (GWT) is designed to work primarily with a Java backend, but a lot of people, myself included, don't really want to mess with the monolithic terror that is a Java backend, and so Google provides a JSON interface as well. In my most recent application, I decided to use JSON to communicate between the GWT front end and Django backend. The results are midly thrilling, so it is not advised that you not follow the link unless you have a strong heart, a good back, and at least one friend named Bubbles for support.

www.lunchtimevoter.com

So, how do you integrate the Django and the GWT? The key part is found in the here. It's a Python-JSON package that will help Django to speak GWT's language. It does a pretty good job of converting standard Pythonisms into JSON. I actually use a modified version, which can be found here. It takes the Python-JSON package and adds the function of interpreting any Python object into JSON as well. Feel free to download and use to your hearts content...

Now, once you have got that, you need to create the object to send, say an object looking something like this, which is the code for a single choice in the lunchtime voter :

class DisplayChoice(object):
__name__ = "DisplayChoice"

def __init__(self,choice):
votes = LunchVote.objects.filter( choice__choiceName__exact = choice.choiceName )
blackballs = LunchBlackball.objects.filter( choice__choiceName__exact = choice.choiceName )

self.choiceName = choice.choiceName;

self.voteList = list()
self.blackballList = list()

for vote in votes:
self.voteList.append(vote.user.displayName)

for blackball in blackballs:
self.blackballList.append(blackball.user.displayName)

As you can see, this code is nothing more than a shell for containing a few essentials that need to be communicated to the frontend. It is then written using the JSON write function with a call such as:

response = HttpResponse(write(displayChoice))
response['Pragma'] = "no cache"
response['Cache-Control'] = "no-cache, must-revalidate"
return response;

Since you'll be updating the AJAX frequently (that's kinda the point of the AJAX stuff isn't it?) you will want to the cache control lines to make sure you get a new copy each time you ask for it. Additionally, you can add some random garbage GET variable to your request from GWT to force the browser to recognize the response as new. After that, you have to decode the thing in your GWT application. This is actually really easy, and for the most part, you can just follow along with the included JSON example. However, it can be a bit tricky to get the JSON decoder working in *your* application. After copying the JSON decoder into your own project structure, it is probably easiest to leave the decoder in its own package and import it using the XML files. Firstly, you want to remove the entry-point from the JSON xml file, just rip the whole line out of there. Secondly, you want to inherit the json classes. As an example, here is what the core xml file for the lunchtime voter looks like:

<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.sample.json.JSON'/>

<!-- Specify the app entry point class. -->
<entry-point class='com.lunchtimevoter.client.Display'/>
</module>

And that's about it. After that, it's all standard django and or gwt stuff, so experiment and have fun :)

13 comments:

Anonymous said...

This is really neat!

Palantar said...

hehe, thanks :)

Google Video said...
This comment has been removed by a blog administrator.
Google Video said...

The modified json.py is not available.
http://lunchtimevoter.com/media/json.py

I would love to use it. :)

Palantar said...

Woops! The file had dissapeared in a server transfer, but it's up again. Cheers :)

Anonymous said...

It would be very helpful if you could write a more indepth tutorial of how you integrated GWT with Django. :)

I found these tutorials useful but it's not using GWT though. So I am still figuring how I can integrate the Django HTML template with the HTML and JS GWT generates.
http://www.b-list.org/weblog/2006/07/31/django-tips-simple-ajax-example-part-1
http://www.b-list.org/weblog/2006/08/05/django-tips-simple-ajax-example-part-2

Moyan said...

Hi gay, from your article I could not find ways to aviod wring java codes to build up client side app.

where is my stupid?

Francisco said...

Hi. Your app is great. It would be very nice if you could post the full code for the application. I hope you consider doing so.

Thanks.

Andriy Drozdyuk said...

More detailed post on this would be great. Please post a follow-up comment if you consider posting something!

Tim "Palantar" Jones said...

Hi - Unfortunately the full code for this app got lost in a computer crash. Since only the compiled code gets stored on the server, I would have to re-write the entire client side.

Then, to make things more interesting, I would also need to completely rewrite the Django site for newforms.

Unfortunately, right now, my interests have turned a bit more conventional. I'm currently working on a Google App Engine/GWT project, and I must say that I greatly prefer it to Django/GWT.

Reasons? Well, with GAE/GWT you can concentrate entirely on Java. No need to keep two entirely different languages in your head at once. You can use RPC calls and share classes from client to server as well, thus avoiding duplicate effort.

Also, at this point Java is a web language is incredibly well established with many high quality frameworks available to publish web files. Also, with GAE you get a free web host for testing. What's not to love?

Andriy Drozdyuk said...

Interesting. Thanks for letting me know!

Is Google App Engine similar to complexity to Django or harder?

Does this mean that you write all of your controllers/views and models in java now or can you still use python?

Does GAE tie you to the google servers for hosting? Or is there a way to host it on a separate machine? What if the GAE servers go down - will you app fail as well?

Hope that's not too many questions for you!

Tim "Palantar" Jones said...

Not at all, glad to be of service :)

Well, Google App Engine is basically a simplified, directed version of J2EE, and as such is more complex but better documented.

In my GAE work, I've followed the the typical Java Servlet J2EE pattern when communicating with the back end, however, you could definitely do all that with python as well. In fact, you can mix and match going so far as running python on top of java using Jython. That does completely negate the 1 language benefit though. Still, it illustrates the relative maturity of the Java language as opposed to Python.

GAE (the Java version anyway) has only a few, easily avoidable non-compliant aspects. So, as long as you don't use the Google-specific extensions to Java, you can simply take your application and run it on any other J2EE server if GAE ever fails to meet a requirement of yours. There is also a built-in Java debugger for local development.

Rodrigo Amaro said...

Hi! I'm from chile and now I'm start to working in a University project with geolocalitacion, C2DM messages and NFC. My work start first with a backend writen in Python with Django framework, a web frontend with GWT and a movile frontend with Android. All the communication with RESTs web services. I feel it's good idea because i can split all the logical part into small modularized projects. Other reason is with the Google App Engine , i don't want to depend on google and I think who a opensource project like django is a most powerfull and independent in my work.

The next weeks I could start all the programming part, please wish me luck

PD: Sorry for my bad english :P