Identity Interface header image

Getting started with the Google App Engine.

The tutorial goes over some basic concepts surrounding Google’s App Engine Framework, demonstrates using the Google App Engine to store data, and using Django templates to create a GeoRss feed that is consumed by Google maps.

Setup your environment

I chose eclipse as my ide.
The nice thing about eclipse is if you add the lib directories of whatever you are using (including the Google App Engine) you will get some intellisense.

Download the necessary components.
Google app engine
Eclipse
Installing Pydev
The documentation helped, but the link was bad. I used http://pydev.sf.net/updates/.

The guts of the python file

?View Code PYTHON
 
import cgi
import os
import wsgiref.handlers
 
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template
 
_DEBUG=True
 
class Business(db.Model):
    ......
 
def main():
    application = webapp.WSGIApplication([
            ('/',MainPage),
            ('/createbusiness.do',BusinessSignup),
            ('/georssfeed.xml',GeoRssFeed)
            ],debug=_DEBUG)
    wsgiref.handlers.CGIHandler().run(application)
 
if __name__ == "__main__":
    main()

The main method is where we map our urls to the classes we have defined within the python file.
Each class that handles requests should have a get or a post method.
When a get or a post occurs it will be routed automagically to the appropriate method.

Creating the table

?View Code PYTHON
class Business(db.Model):
    name = db.StringProperty()
    description = db.StringProperty(multiline=True)
    url = db.URLProperty()
    location = db.StringProperty()
    latitude = db.StringProperty()
    longitude = db.StringProperty()
    address = db.StringProperty()
    created = db.DateTimeProperty(auto_now_add=True)

Description can contain line breaks so we specify multiline=True
Created is of type DateTime and has the property auto_now_add set to true
created is set to the current time the first time the model instance is stored in the datastore, unless the property has already been assigned a value.

There is also an auto_now property that can be used to set the current time each time the record is created or updated. Useful for modified dates.


Handling the request

In one of googles examples(Task List) they used a base class for the request.
Here is my modified version.

?View Code PYTHON
class BaseRequestHandler(webapp.RequestHandler):
    """Supplies a common template generation function"""
    def generate(self,template_name,template_values={}):
        values = {
                  'request': self.request,
                  'debug': self.request.get('deb'),
                  'application_name': 'Local Business Directory'
                  }
 
        values.update(template_values)
        directory = os.path.dirname(__file__)
        path = os.path.join(directory,os.path.join('templates',template_name))
        self.response.out.write(template.render(path,values,debug=_DEBUG))

This does a few nice things.

?View Code PYTHON
        values = {
                  'request': self.request,
                  'debug': self.request.get('deb'),
                  'application_name': 'Local Business Directory'
                  }
        values.update(template_values)

This sets up an array of base values that will be passed into the template.
In other methods that use base request, we will add other objects to this array. So our html templates can process data.
The last line values.update is where the two arrays gets merged.

?View Code PYTHON
        path = os.path.join(directory,os.path.join('templates',template_name))

In this application I created a templates folder to separate the html from the code. This line just adds the template_name to the /templates path.

?View Code PYTHON
    self.response.out.write(template.render(path,values,debug=_DEBUG))

And finally
Write the request out.

Using the BaseRequestHandler

?View Code PYTHON
class MainPage(BaseRequestHandler):
    def get(self):
 
        #Get all of the businesses
        businesses = Business.all().order('-created')
 
        self.generate('index.html', {
                                     'businesses': businesses
                                     })

Here is a simple example of querying all of the businesses ordered by created date.
We then call the generate method on the BaseRequestHandler, passing in our additional objects, along with the template name.

Using Templates
The Google App Engine uses the Django templating engine. W00t

The for loop

?View Code PYTHON
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}

The if statement(there are several varieties)

?View Code PYTHON
{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% else %}
    No athletes.
{% endif %}
 
{% ifequal user.id comment.user_id %}
    ...
{% endifequal %}

In the spirit of python, there are a lot of functions that Django gives you.
Examples:
timesince: Formats a date as the time since that date (e.g., “4 days, 6 hours”).
phone2numeric: Converts a phone number (possibly containing letters) to its numerical equivalent. For example, ‘800-COLLECT’ will be converted to ‘800-2655328′.

More Information on Django templates

In order to display a list of businesses I am just using a simple for loop and creating a row each time.

<div class="table">
	<table>
		<tr>
			<th>Business Name</th>
			<th>Address(Address, City, State)</th>
			<th>Description</th>
			<th>Url</th>
			<th>Location</th>
			<th>Latitude</th>
			<th>Longitude</th>
		</tr>
		</tr>
		{% for business in businesses %}
		<tr id="row{{ forloop.counter}}">
		<td class="main" 
		  <div class="name">{{ business.name }}</div>
		</td>
		<td class="members">
			{{ business.address }}
		</td>
		<td class="members">
			{{ business.description }}
		</td>
		<td class="members">
			{{ business.url }}
		</td>
		<td class="members">
			{{ business.location }}
		</td>
		<td class="members">
			{{ business.latitude }}
		</td>
		<td class="members">
			{{ business.longitude }}
		</td>
 
		</tr>
		{% endfor %}
	</table>
</div>

Entering Data

Two pieces of code were necessary for this
Plumbing in the python file

?View Code PYTHON
class BusinessSignup(webapp.RequestHandler):    
    def post(self):
        business = Business()
 
        business.name = self.request.get("txtBusinessName")
        business.address = self.request.get('txtAddress')
        business.description = self.request.get('txtDescription')
        business.url = self.request.get('txtUrl')
        business.location = self.request.get('txtLocation')
        business.latitude = self.request.get('txtLatitude')
        business.longitude = self.request.get('txtLongitude')
 
        business.put()
        self.redirect('/')

This just grabs from the data from the request and sets each property on our business object.
Then calls put.
put is an instance method that saves the data to the database.
delete, to_xml, is_saved, are a couple of other useful instance methods.

    <form action="/createbusiness.do" method="post" id="businessform">

Tells the form to post to the specified address.

Bringing it all together

application: yourapplication
version: 1
runtime: python
api_version: 1
 
handlers:
- url: /static
  static_dir: static
 
- url: /.*
  script: localbusinesslocator.py

The app.yaml is where your external url mapping occurs.
If you wanted to use several python files, this is where that would happen.
More Info can be found here

Testing the application
usr/local/google_appengine/dev_appserver.py /sourcedirectory/

Hopefully this fills in some gaps left by Googles tutorial.

The next installment of the series will go over displaying the data in the GeoRss format and displaying it on google maps.

5 Comments on “Getting started with the Google App Engine.”

  1. #1 Ahsan
    on May 18th, 2008 at 10:48 am

    Hi there,

    Nice write up. Really liked the idea of using a BaseRequestHandler. Coming from the CakePHP camp (yeah I am more into PHP!), I was wondering how about using abit of convention to load a template file automatically? The templates can have the same name as the RequestHandler (requesthandername.html), and make the Base Request Handler to load the template with the same name. That way, we will just need to pass the data to the template, and the Base Request Handler will load the template file with the same name.

    What do you think? Does that go with the Python way?

  2. #2 jonshern
    on May 18th, 2008 at 6:42 pm

    It certainly would work.
    Kind of a ruby style, convention over configuration.
    Personally I like to be explicit, so passing around the template is a small price to pay for this.
    If another programmer comes along, they can see exactly what I am doing.
    It really comes down to personal preference.

  3. #3 Mats
    on May 20th, 2008 at 7:27 am

    Very nice tutorial. Looking forward to the next part!

  4. #4 state id template download
    on May 25th, 2008 at 7:14 am

    [...] Django templates to create a GeoRss feed that is consumed by Google maps. Setup your environment Ihttp://jonshern.com/2008/05/18/getting-started-with-the-google-app-engine/State Template Download, Upgrade to Latest Version :: WebTools …Download state template Package - [...]

  5. #5 Pablo
    on Jun 1st, 2008 at 9:51 am

    Very interesting tutorial. Looking forward to the second part.
    Regards,
    Pablo

Leave a Comment