In this tutorial, I’ll be showing you how to make a functional AJAX application on Google App Engine. There are two ways to do this, the first being to use a framework such as JQuery, the second being to write the javascript by hand. I will be showing you how to do both, and in such a way that a beginner can make sense of it easily, while more advanced users of App Engine can also benefit.
So I’m going to split the tutorial up into two parts, and each part will have a separate example for you to work with. Here are the bookmarks to each section, and you can decided which way you want to do this. Personally, I find JQuery easier, but it will require that you learn some new things if you are only familiar with Javascript.
AJAX with JQuery and App Engine
For the JQuery part, take a look at this message generator that I quickly made. This is what we will be making if you are following along, so make sure that you take a look at it before we get started.
I am going to assume that you have already set up an App Engine Application, if not, you can check out this tutorial on Getting Started With Web Application Development, which explains exactly how you can do this. Then we have to create the page on which the AJAX will function, I have called this “magic.html”, you call it whatever you want. So let’s set up the basic format (I’ll try to use exactly what I have made for the message generator application, which actually validates on w3 validator). The first part before the line break just includes the obvious html set-up, like the title of the page, and description, and the second section is the style. This is up to you to decided what is appropriate for your application.
<!DOCTYPE HTML PUBLIC"-// W3C//DTD HTML 4.01 Transitional//EN"" http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>The Message Generator
</title>
<META NAME="Description" CONTENT="Add your thoughts and see what others are saying"/>
<style type="text/css">
body{ width:100%; margin:0px; overflow:none; }
p{ font-size: 40pt; font-family: "Arial"; font-weight: 800; margin-bottom:0px; padding-bottom:0px; }
#messages { width:94%; margin-right:3%; margin-left:3%; height: 80%; padding:0px; margin:0px; }
#credit { font-size: 14pt; font-family: "Arial"; color: #BABABA; font-weight: 500; padding-top:0px; margin-top:0px; }
#add { position:absolute; bottom:60px; width:100%; text-align:center; line-height:150%; padding:0px; margin:0px; }
#add input[type=text]{ width:200px; }
a { color: #DADADA; text-decoration:none; }
#message { color: #black; size: 16pt; margin-bottom:5px; }
<div>
<div>add your message
</div>
<input type="text"/>
-
<input id="addcred" style="width: 100px;" value="anonymous"/>
<input id="addmessage" style="margin-top: 5px;" value="add"/>
</div>
Okay, so this is what the page looks like. You’ll notice that I haven’t closed the page, because we still have to add the JQuery. Let me explain what’s going on here: the “messages div” is where the messages are going to pop up, and it seperated into “magicresponse”, which is the actual message, and “credit”, which is the div for the author’s name. The “add” div is there for the form to add. You’ll see that this isn’t really a form as such, because we are going to be using AJAX to execute all of our submit functionality.
First we need to load the JQuery into the page:
<script src="”http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js”" type="”text/javascript”"> </script>
Now let’s use it for something:
<script type="”text/javascript”">// <![CDATA[
$(document).ready(function(){
var messagesString = “{{messages}}”;
var messages = messagesString.split(“|”);
x = 1;
$(“#magicresponse”).html(messages[0].split(“-”)[0]);
$(“#credit”).html(” – ” messages[0].split(“-”)[1]);
$(“#magicresponse”).css({“color”:messages[0].split(“-”)[2], “margin-left”:messages[x].split(“-”)[3],”padding-top”:messages[x].split(“-”)[4]});
$(“#credit”).css({“margin-left”:messages[0].split(“-”)[3]});
$(“#messages”).fadeIn(“slow”);
In this function so far, the script is loading the “messages” from our application, and then splitting it into individual messages. Next, it sets a variable, x, to 1 so that it can keep track of which message it it on in a loop that will follow. After that it shows the first message on the screen by fading it in. Here you can get a good idea how how the application is going to work. The first line after the variables sets the “magicresponse” div to show the first message, using JQuery’s function ‘.html().’, which is the equivalent of javascript’s ‘innerHtml’. It does a similar thing next, by setting the ‘credit’ div to show the first message’s author. After that, it uses JQuery’s ‘.css()’ function to set the div’s style to show text with a certain color and margin. The last line tells the ‘messages’ div to fade in, using JQuery’s predefinted ‘fadeIn’ function.
This is where things get more exciting from a JQuery standpoint. The following code sets a timer for 5 second (5000 milliseconds) intervals, after which it fades the messages out, waits half a second before changing to a new message, and fades it in again.
$.timer(5000, function() {
if (x==messages.length){
x=0;
}
$("#messages").fadeOut("slow");
window.setTimeout(function() {
$("#messages").fadeIn("slow");
$("#magicresponse").html(messages[x].split("-")[0]);
$("#credit").html(" - " messages[x].split("-")[1]);
$("#magicresponse").css({"color":messages[x].split("-")[2], "margin-left":messages[x].split("-")[3],"padding-top":messages[x].split("-")[4]});
$("#credit").css({"margin-left":messages[x].split("-")[3]});
x = 1;
}, 500);
});
Next, we need to create an event function for adding new messages. We attach this to the ‘add’ button with JQuery’s ‘live’ function, which will make sure that it keeps the function attached after the ajax has been called – if you don’t understand what I mean by that, then you don’t need to worry. Just know that if you are using AJAX functions in JQuery to change things on the page, then you need to use ‘live’ rather than ‘click’.
$("#addmessage").live("click", function () {
var new_message = $("#first").val();
var credit = $("#addcred").val()
var data = "first="+first + "&credit=" + credit;
$("#first").val("");
$("#message").fadeOut("slow");
This functions tells the browser that when the ‘addmessage’ button is clicked, it must set the variables, ‘new_message’ to the value of the message text box. It must then set a ‘credit’ variable to the value of the author’s name textbox, and then it must create a new ‘data’ variable, which combines those two variables into a format that our Python can understand. It then sets the message text box to show nothing, to let the user know that the message has been sent. It fades out the ‘message’ div (which had said “add your message”).
In the next bit, we use JQuery’s ‘ajax()’ function to send our data. It takes in ‘type’, which should be set to ‘post’, the url that the data should be sent to, which I’ve set to this same page, the data to be sent, and what to do when all this is finished. The success function takes in ‘responseText’, which is the information that our Python code will send back. I’ve made it so that it will either return “sorry” if the message has already been added, or the updated array of messages.
$.ajax({
type: "POST",
url: "/i-stat",
data: data,
success: function(responseText){
if (responseText=="sorry"){
$("#message").fadeIn("slow");
$("#message").html("Sorry, that message has already been added.");
window.setTimeout(function() {
$("#message").fadeOut("slow");
window.setTimeout(function (){
$("#message").fadeIn("slow");
$("#message").html("add your message");
},1000);
}, 4000);
}
else{
$("#message").fadeIn("slow");
$("#message").html("Added:
"+first + "
"+ "- " + credit)
messages = responseText.split("|");;
window.setTimeout(function() {
$("#message").fadeOut("slow");
window.setTimeout(function (){
$("#message").fadeIn("slow");
$("#message").html("add your message");
},1000);
}, 4000);
}
}
});
});
});
Next we just need to make a new timer for jQuery, which is really just for this application, so you don’t need to know how to do it, but I’ll include it anyway:
jQuery.timer = function (interval, callback)
{
var interval = interval || 100;
if (!callback)
return false;
_timer = function (interval, callback) {
this.stop = function () {
clearInterval(self.id);
};
this.internalCallback = function () {
callback(self);
};
this.reset = function (val) {
if (self.id)
clearInterval(self.id);
var val = val || 100;
this.id = setInterval(this.internalCallback, val);
};
this.interval = interval;
this.id = setInterval(this.internalCallback, this.interval);
var self = this;
};
return new _timer(interval, callback);
};
Okay, now we can start with the python stuff! First the basics, with a datastore model to hold all our messages:
import cgi import os from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app from google.appengine.ext.webapp import template from google.appengine.ext import db class Messages(db.Model): content = db.StringProperty() date = db.DateTimeProperty(auto_now_add = True) credit = db.StringProperty()
Next, the class needed to process everything the application is going to do. It include a get method, which generates the “index” screen, if you will. It also includes a method which gets all of the messages, assigns random colours and margins to each message. And another method which allows for new data to be added.
class Magician(webapp.RequestHandler):
def get(self):
messages = self.get_messages()
values = {"messages": messages}
path = os.path.join(os.path.dirname(__file__), "magic.html")
self.response.out.write(template.render(path, values))
def get_messages(self):
from random import choice
from random import shuffle
from random import random
colors = ["#7E949E", "#AEC2AB","#EBCEA0", "#FC7765", "#FF335F", "#E0DC8B", "#F6AA3D", "#ED4C57", "#574435", "#6CC4B9", "#540633",
"#009050","#261826", "#800F25", "#F02311", "#5F7F96", "#AA2F48", "#C0ADDB", "#7078E6"]
messages = ""
keys = []
query = db.GqlQuery("SELECT __key__ FROM Crap ORDER BY date DESC")
results = query.fetch(1000)
for result in results:
keys.append(result)
shuffle(keys)
num = 0
if len(keys) > 400:
num = 400
else:
num = len(keys)
for i in range(num):
if db.get(keys[i]):
result = db.get(keys[i])
if result.content != "":
x = round(random()*400)
y = round(random()*50)
color = choice(colors)
content = cgi.escape(result.content).replace(""", "'")
messages += content + "-" + cgi.escape(result.credit) + "-"+color+"-"+str(x)+"px-"+str(y)+"px|"
return messages
def post(self):
first = self.request.get("first")
credit = self.request.get("credit")
message = first
query = db.GqlQuery ("SELECT * FROM Crap WHERE content=:1", message)
done = False
results = query.fetch(1)
for result in results:
done = True
if done == True:
text = "sorry"
else:
crap = Crap()
crap.content = message
crap.credit = credit
crap.put()
text = self.get_messages()
self.response.out.write(text)
Calling self.response.out.write will give our page the "responseText" that it requires. Now we just finish up:
application = webapp.WSGIApplication([('/i-stat', Magician)])
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
And that’s it! That is a complete tutorial on how to use AJAX with JQuery and App Engine. Well done!
Hand-Coded AJAX with App Engine
In this post I will describe how to create an AJAX application, using Google App Engine with Python and Django. I’m going to make it as simple as possible, because it is really quite simple for the most part, so that anyone using App Engine can quickly put together a smooth, elegant Ajaxian feature by reading this post. An example of an AJAX function would be the commenting section on this blog (at the bottom of this post), which can add comments without reloading the entire post.
First of all, it is possible to do this using JQuery or Prototype as a Javascript framework, but I’m rather going to write my own javascript here and keep everything as clean and reusable for everybody as I can. So here goes – let’s start off by defining some javascript functions that will process the requests:
quite simple, returns an XMLHttpRequest:
function createXmlHttpRequest() {
try {
if (typeof ActiveXObject != ‘undefined’) {
return new ActiveXObject(‘Microsoft.XMLHTTP’);
} else if (window["XMLHttpRequest"]) {
return new XMLHttpRequest();
}
} catch (e) {
changeStatus(e);
}
return null;
};
The function downloadUrl() is the one you’re going to call when you need to create an AJAX function. It uses another method, defined previously, called createXmlHttpRequest. It takes in four parameters, the URL to which you’re sending the request, the type of request (POST/GET), the parameters you’re sending (like “comment=’hello’”), and the function to run once completed. The ‘state’ of the request is monitored, in order to run the callback method once everything is completed. ‘request.open’ sets the necessary encoding for the POST method, and sends the data to through the specified URL.
function downloadUrl(url, type, data, callback) {
var status = -1;
var request = createXmlHttpRequest();
if (!request) {
return false;
}
request.onreadystatechange = function() {
if (request.readyState == 4) {
try {
status = request.status;
} catch (e) {
}
if (status == 200) {
callback(request.responseText);
request.onreadystatechange = function() {};
}
}
}
request.open(type, url, true);
if (type == "POST") {
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", data.length);
request.setRequestHeader("Connection", "close");
}
try {
request.send(data);
} catch (e) {
changeStatus(e);
}
};
function downloadScript(url) {
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}
Next, we write some HTML to use our newly defined AJAX capability! In the example below, a user can submit some text through a textarea, which will go through to another page and be used by Python. The next bit includes all of the html and javascript needed, so if you’re copying, just take the following code:
<body>
{{response}}
<h3>Magic Textbox</h3>
<textarea rows="3" cols="60"></textarea>
<button onClick="runMagic()">Run Magic</button>
<script>
function runMagic(){
var text = document.getElementById("magicbox").value;
downloadUrl("/magic", "POST", "text=" + text, completed);
}
function completed(responseText){
document.getElementById("magicresponse").innerHTML = responseText;
}
function downloadUrl(url, type, data, callback) {
var status = -1;
var request = createXmlHttpRequest();
if (!request) {
return false;
}
request.onreadystatechange = function() {
if (request.readyState == 4) {
try {
status = request.status;
} catch (e) {
}
if (status == 200) {
callback(request.responseText);
request.onreadystatechange = function() {};
}
}
}
request.open(type, url, true);
if (type == "POST") {
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", data.length);
request.setRequestHeader("Connection", "close");
}
try {
request.send(data);
} catch (e) {
changeStatus(e);
}
};
function downloadScript(url) {
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}
function createXmlHttpRequest() {
try {
if (typeof ActiveXObject != 'undefined') {
return new ActiveXObject('Microsoft.XMLHTTP');
} else if (window["XMLHttpRequest"]) {
return new XMLHttpRequest();
}
} catch (e) {
changeStatus(e);
}
return null;
};
// ]]></script>
Okay, now we’ve got all the code that will go into our html page. Save this page, with all the code as “magic.html” Now I’m going to write some Python:
import cgi
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
class BaseRequestHandler(webapp.RequestHandler):
def generate (self, fileIn, values):
template_values={}
template_values.update(values)
path = os.path.join(os.path.dirname(__file__), fileIn)
self.response.out.write(template.render(path, template_values))
def wizard (self, text):
text_li = text.split()
new_text = ""
for i in text_li:
new_text += i +" length: "+ str(len(i)) + "
"
return new_text
class Magician(BaseRequestHandler):
def get(self):
response = "welcome to the magic box app!"
values = {"response": response}
self.generate("magic.html", values)
class Magic (BaseRequestHandler):
def post(self):
text = self.request.get("text")
self.response.out.write(self.wizard(text))
application = webapp.WSGIApplication([('/index', Magician),
('/magic', Magic)])
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Well, if you run this code on your App Engine url or localhost, you should have a pretty neat AJAX application! I hope this tutorial proves useful for those who are in the intermediary stages of using Google App Engine – it is not another ‘Get Started with App Engine’ post, because there are already a million of these online for beginners.
Sincerely,

pythoughts is legend
man, i’ve heard a lot about python and kinda wrote it off but the functionality is stellar. completely stand alone. took me a little while to figure out what your magic app actually did
but amazing how well it works…
Hi pythoughts,thanks a lot for the useful link. I was wondering how could i tweak your code to add a ajax reorderlist on google app engine?
Nice tutorial. I’ll be trying it in my next test dev. Thanks.
Sure, I’m glad you liked it.
I tried the AJAX version of the software with App Engine and it didn’t work. Nothing ever shows up. Are the magic.html and python listings I need besides app.yaml?
Hi Nick,
This article is actually very old – about two years, so some things I’m not too sure about. One thing that I do know is that you probably need to set up a table called “Crap” that I used to store all of the messages from the JQuery part.
The plain javascript part of this tutorial is actually the more straight-forward part (the post itself is divided into two sections), so if you’re getting started with using App Engine, that’s a better part to look at – though I don’t know your level of experience obviously. I know that there’s nothing extra that you have to download in any of this though.
I hate how there is no date.
You wanted dates? You got dates
Syntax highlighting would make the code examples much easier to digest – particularly important in python don’t you think? Otherwise thanks!
Hi,
Appreciate your article.
Is it possible to upload the zip of the entire source? Its easy to build and run than collect different pieces of code and try to make it work.
Thanks in advance,
Naidu
can you provide the working example link please, many thanks
http://1.pythoughtsblog.appspot.com/i-stat
Any idea about autocomplete on python appengine?
Thanks
Hi!
I’m very new to all of these concepts (though rather experienced in programming) and can’t really get the jQuery tutor to work.
Could you please provide a link to the sourcecode? It would be SO much easier to start tweaking when it’s up and running rather than trying to figure out which part is wrong from all that copy-pasting.
I would really appreciate it since I’m kind of stuck with getting a simple AJAX+GAE example to work. Can’t seem to find a complete one and don’t seem to understand enough to paste one together. =)
Thanks a lot!
/KJ
I tried to run you code but i cudnt. I get message in browser ‘Link is Broken’ i did all the indentation corrections.I want to make chat application so basically i just want to reflect the message on the fly on every user.Plz suggest something ?
Finally i managed to run your code.There are some errors in your HTML page you.you have not given id “magicbox” and you application needs one more element with id “magic response” and few app.yaml changes.Can u suggest anything for chat application. ?
You could do a javascript call to a python file that checks the database for any new database entries, every 2 seconds say. I don’t know if that’s the most efficient way to do it, but that’s where I would start. It’s fairly basic AJAX, I’m sure there are many tutorials available.
Please tell me how to add image in template …. yaml.py not accepting my static_dir …I am using Windows 7
GET http://127.0.0.1:9001/bgimage.jpg 404 (Not Found)
Thanks a lot. Your post was helpful getting me started on Ajax with Jquery.
hey, I think your code examples are missing some parts…
i added these two ids to make it works:
magicbox and magicresponse
Run Magic