Tech and travel

Google App Engine

2008-04-14

Python‘s creator, Guido Van Rossum, has been hinting at this for a while, and it’s finally here : Google App Engine. It’s a way to build and host web apps on the Google servers.

I put a small app together, which is a very simple variation on the ‘The Django Form Validation Framework on Google App Engine‘ article. It let’s you login, and store some data on workouts. On to some code :

import cgi
  import wsgiref.handlers
  import os

  from google.appengine.api import users
  from google.appengine.ext import db
  from google.appengine.ext import webapp
  from google.appengine.ext.webapp import template

  from google.appengine.ext.db import djangoforms

Firstly, a lot of imports are done to get everything we need.

class Workout(db.Model):
    minutes = db.IntegerProperty()
    distance = db.FloatProperty()
    calories = db.IntegerProperty()
    date = db.DateProperty(required=True)
    added_by = db.UserProperty()

Then a class is defined that is derived from a database Model base class. This will be stored in a database from Google called the Datastore. It contains fields for the minutes, the distance cycled and so on. The only mandatory field is the date. There is also a user field. This will be filled in when the user logs in. It also keeps the data private per user.

class WorkoutForm(djangoforms.ModelForm):
    class Meta:
      model = Workout
      exclude = ['added_by']

Next, a form object is created. This is based on the model defined above, and it will not display the added_by field.

class MainPage(webapp.RequestHandler):
    def get(self):
      user = users.get_current_user()
      if user:
        self.response.out.write('form goes here')
        self.response.out.write(WorkoutForm())
        self.response.out.write('remainder of form')
      else:
        self.redirect(users.create_login_url(self.request.uri))

The MainPage class handles request for a page. Here the get request is handled. If the user is logged in, it displays the form. If not, a redirection is done to Google’s login page.

def post(self):
      data = WorkoutForm(data=self.request.POST)
      if data.is_valid():
        # Save the data, and redirect to the view page
        entity = data.save(commit=False)
        entity.added_by = users.get_current_user()
        entity.put()
        self.redirect('/workouts.html')
      else:
        # Reprint the form
        self.response.out.write('beginning of form')
        self.response.out.write(data)
        self.response.out.write('remainder of form')

A post request (from the form in the get method) is handled by the post method. It saves the data in the database if it is valid. If not, for example if the date is not filled here, it will display the data again with an error message.

class WorkoutPage(webapp.RequestHandler):
    def get(self):
      user = users.get_current_user()
      if user:
        query = db.GqlQuery("SELECT * FROM Workout WHERE added_by = :1 ORDER BY date DESC",
                            users.get_current_user())

        workouts=[]
        for workout in query:
            workouts.append({'date': workout.date.strftime("%x"),
                             'minutes': workout.minutes,
                             'distance': workout.distance,
                             'calories': workout.calories
                            })

        template_values = {
          'workouts': workouts,
        }

        path = os.path.join(os.path.dirname(__file__), 'workout.html')
        self.response.out.write(template.render(path, template_values))
      else:
        self.redirect(users.create_login_url(self.request.uri))

The WorkoutPage class handles a get request that shows the results stored in the database. It uses a template called workout.html, which is not shown. All the necessary data is gathered and then the template is rendered with that data in the template.render call.

def main():
    application = webapp.WSGIApplication(
                                         [('/', MainPage),
                                          ('/workouts.html', WorkoutPage),
                                          ],
                                         debug=True)
    wsgiref.handlers.CGIHandler().run(application)

  if __name__=="__main__":
    main()

Lastly, the URLs are setup. The mainpage is mapped to / and the WorkoutPage class to /workouts.html.

The app, which is very Web 0.1, can be found here. After you login with your Google ID, you can start logging those workouts.

A few things to remark :

  • this code could do with a bit of a cleanup, which is all my fault
  • the data is stored on Google’s servers. You may not like that.
  • a Google ID is needed to login here (this can probably be changed)

All said and done, Google App Engine is a nice piece of work. It took about an hour to put all of this together and to upload it to the Google servers. So Google seems to have their homework about making it developer friendly. How well it will work for real apps is another matter. Only time will shows us that, and this is definitely still a beta. But it does look promising.

Copyright (c) 2024 Michel Hollands