I am completely novice at AJAX. I am familiar with HTML/CSS, jQuery and beginner at GAE and Python.
In an effort to understand how AJAX works, I would like to know h
Ok Sir here we go... A simple app with one story and infinite votes... ;-)
app.yaml
application: anotherappname
version: 1
runtime: python27
api_version: 1
threadsafe: true
default_expiration: "0d 0h 5m"
libraries:
- name: jinja2
version: latest
- name: webapp2
version: latest
handlers:
- url: .*
script: main.app
main.py
import logging
from controllers import server
from config import config
import webapp2
app = webapp2.WSGIApplication([
# Essential handlers
('/', server.RootPage),
('/vote/', server.VoteHandler)
],debug=True, config=config.config)
# Extra Hanlder like 404 500 etc
def handle_404(request, response, exception):
logging.exception(exception)
response.write('Oops! Naughty Mr. Jiggles (This is a 404)')
response.set_status(404)
app.error_handlers[404] = handle_404
models/story.py
from google.appengine.ext import ndb
class Story(ndb.Model):
title = ndb.StringProperty(required=True)
vote_count = ndb.IntegerProperty(default = 0)
controllers/server.py
import os
import re
import logging
import config
import json
import webapp2
import jinja2
from google.appengine.ext import ndb
from models.story import Story
class RootPage(webapp2.RequestHandler):
def get(self):
story = Story.get_or_insert('Some id or so', title='A voting story again...')
jinja_environment = self.jinja_environment
template = jinja_environment.get_template("/index.html")
self.response.out.write(template.render({'story': story}))
@property
def jinja_environment(self):
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(
os.path.join(os.path.dirname(__file__),
'../views'
))
)
return jinja_environment
class VoteHandler(webapp2.RequestHandler):
def post(self):
logging.info(self.request.body)
data = json.loads(self.request.body)
story = ndb.Key(Story, data['storyKey']).get()
story.vote_count += 1
story.put()
self.response.out.write(json.dumps(({'story': story.to_dict()})))
and finally
views/index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<h2>{{story.title}}</h2>
<div>
<span class="voteCount">{{story.vote_count}}</span> | <a href="javascript:VoteUp('{{story.key.id()}}');" >Vote Up Story</a>
</div>
<script>
function VoteUp(storyKey){
$.ajax({
type: "POST",
url: "/vote/",
dataType: 'json',
data: JSON.stringify({ "storyKey": storyKey})
})
.done(function( data ) { // check why I use done
alert( "Vote Cast!!! Count is : " + data['story']['vote_count'] );
$('.voteCount').text(data['story']['vote_count']);
});
};
</script>
</body>
</html>
Assemble, read it's simple enough and run. If you need a working git example just comment.
githublink (as from comments)
Here is a little prototype web app on GitHub to test how to handle error messages in HTML form submissions with AJAX, Python and Google App Engine. It will give a starting point to see how these three pieces of technology mesh together. You can test this "app" on https://ajax-prototype.appspot.com/
Here is how it works on the client-side:
This htlm form submission is used:
<form method="post" action="javascript:ajaxScript();">
<label>Please pick a name</label>
<input id="input" type="text">
<input type="submit">
<div id="error" style="color:red"></div>
It will trigger the JavaScript function ajaxScript
:
function ajaxScript() {
var input = $("#input").val();
$.ajax({
type: "POST",
url: "/",
data: JSON.stringify({
"name": input
}),
dataType: "json"
})
.done(function(jsonResponse) {
$("#error").html(jsonResponse.message);
});
}
The jQuery .ajax()
method handles the request while the .done()
method will eventually handle the response that it gets from the server.
On the server-side:
The main.py
file handles the server side of the business using our handler class AjaxHandler
, which inherits from the GAE builtin class webapp2.RequestHandler
Within this class, the post
method handles the AJAX request:
def post(self):
data = json.loads(self.request.body)
username = data["name"]
if not re.match(r"^[a-zA-Z0-9_-]{3,20}$", username):
if len(username) < 3:
message = "Your name must be at least 3 characters long."
else:
message = "Allowed characters are \
a-z, A-Z, 0-9, underscores \
and hyphens."
else:
message = "Congrats!"
self.response.write(json.dumps({"message": message}))
Basically, the handy json
module provides the two key Python ingredients
json.loads
handles the data that the browser sends to the server.json.dumps
handles the data sent by the server in response to the browser's request.self.request.body
argument of json.loads
is the only less common piece of GAE that is used in the process, as it is specific to the task. As its name suggests, it gets the body from the Ajax request sent by the client.