ONLamp.com
oreilly.comSafari Books Online.Conferences.

advertisement


Getting Started with the Google App Engine
Pages: 1, 2, 3

Backwards First

Now that we have helloworld out of the way, let's crack open the source code for our instructional application and break it down. At this point you will need to check it out from subversion, and then change into the directory to run the sample code. Again to run the application you just need to type:



dev_appserver.py .

I would leave this running in a terminal window as it will automatically figure out when you make changes. In another window in your favorite text editor open up change.py. This one file does most of the work of our application, and here it is for posterity:

    #!/usr/bin/env python2.5
    #Noah Gift

    import decimal
    import wsgiref.handlers
    import os

    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

    class ChangeModel(db.Model):
        user = db.UserProperty()
        input = db.IntegerProperty()
        date = db.DateTimeProperty(auto_now_add=True)

    class MainPage(webapp.RequestHandler):
        """Main Page View"""

        def get(self):
            user = users.get_current_user()

            if users.get_current_user():
                url = users.create_logout_url(self.request.uri)
                url_linktext = 'Logout'
            else:
                url = users.create_login_url(self.request.uri)
                url_linktext = 'Login'

            template_values = {
            'url': url,
            'url_linktext': url_linktext,
            }
            path = os.path.join(os.path.dirname(__file__), 'index.html')
            self.response.out.write(template.render(path, template_values))

    class Recent(webapp.RequestHandler):
        """Query Last 10 Requests"""

        def get(self):

            #collection
            collection = []
            #grab last 10 records from datastore
            query = ChangeModel.all().order('-date')
            records = query.fetch(limit=10)

            #formats decimal correctly
            for change in records:
                collection.append(decimal.Decimal(change.input)/100)

            template_values = {
            'inputs': collection,
            'records': records,
            }

            path = os.path.join(os.path.dirname(__file__), 'query.html')
            self.response.out.write(template.render(path,template_values))

    class Result(webapp.RequestHandler):
        """Returns Page with Results"""
        def __init__(self):
            self.coins = [1,5,10,25]
            self.coin_lookup = {25: "quarters", 10: "dimes", 5: "nickels", 1: "pennies"}

        def get(self):
            #Just grab the latest post
            collection = {}

            #select the latest input from the datastore
            change = db.GqlQuery("SELECT * FROM ChangeModel ORDER BY date DESC LIMIT 1")
            for c in change:
                change_input = c.input

            #coin change logic
            coin = self.coins.pop()
            num, rem  = divmod(change_input, coin)
            if num:
                collection[self.coin_lookup[coin]] = num
            while rem > 0:
                coin = self.coins.pop()
                num, rem = divmod(rem, coin)
                if num:
                    collection[self.coin_lookup[coin]] = num

            template_values = {
            'collection': collection,
            'input': decimal.Decimal(change_input)/100,
            }

            #render template
            path = os.path.join(os.path.dirname(__file__), 'result.html')
            self.response.out.write(template.render(path, template_values))

    class Change(webapp.RequestHandler):

        def post(self):
            """Printing Method For Recursive Results and While Results"""
            model = ChangeModel()
            try:
                change_input = decimal.Decimal(self.request.get('content'))
                model.input = int(change_input*100)
                model.put()
                self.redirect('/result')
            except decimal.InvalidOperation:
                path = os.path.join(os.path.dirname(__file__), 'submit_error.html')
                self.response.out.write(template.render(path,None))

    def main():
        application = webapp.WSGIApplication([('/', MainPage),
                                            ('/submit_form', Change),
                                            ('/result', Result),
                                            ('/recent', Recent)],
                                            debug=True)
        wsgiref.handlers.CGIHandler().run(application)

    if __name__ == "__main__":
        main()

As a backwards first tutorial, lets start by looking at either the version running at http://greedycoin.appspot.com, or your development version at http://localhost:8080/. There is a pumpkin colored theme that has two floating boxes, on the left is a form that lets you input change, and on the right there is a navigation box. These pretty, or ugly, colors, and layout are just a combination of django templating and CSS. The django templates can be found in the main directory, and the css I used is found in stylesheets. This really has little to do with Google App Engine, so I will just refer you to Django templating reference material if you are not familiar with them.

Now that we have covered this, let's actually get into some Google App Engine specifics. If you notice the "Login" link in the right navigation box, it is made possible by the clever user authentication API. Here is what that actual code looks like:

    class MainPage(webapp.RequestHandler):
        """Main Page View"""

        def get(self):
            user = users.get_current_user()

            if users.get_current_user():
                url = users.create_logout_url(self.request.uri)
                url_linktext = 'Logout'
            else:
                url = users.create_login_url(self.request.uri)
                url_linktext = 'Login'

            template_values = {
            'url': url,
            'url_linktext': url_linktext,
            }
            path = os.path.join(os.path.dirname(__file__), 'index.html')
            self.response.out.write(template.render(path, template_values))

There is a class that inherits from webapp.RequestHandler and if you define a get method you can make a page that checks to see if a user is logged in or not. If you notice the few lines at the bottom, you will see that the user information gets tossed into the template system and then gets rendered to the Django template file index.html. What is incredibly powerful, is that it is trivial to leverage the Google User Accounts database to create authorization for pages. If you look at the code above it is as simple as saying:

    user = users.get_current_user()

            if users.get_current_user():

I would suggest fiddling around with this code and trying to add code that only shows up for authenticated users. You don't even need to understand how things work, you could just use the existing conditional statements to do something.

Pages: 1, 2, 3

Next Pagearrow





Sponsored by: