<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1856743739898714601</id><updated>2011-11-27T16:26:13.646-08:00</updated><title type='text'>Working Clouds</title><subtitle type='html'>What works, and what doesn't, with the Google_App_Engine instance of Cloud_Computing</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://workingclouds.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://workingclouds.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Greg Bryant</name><uri>http://www.blogger.com/profile/13408526593029789018</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1856743739898714601.post-3515756750537102015</id><published>2008-11-28T08:13:00.001-08:00</published><updated>2009-03-16T16:00:27.701-07:00</updated><title type='text'>Passing Keys</title><content type='html'>&lt;hr&gt;The current version of this article and sequence can be found at &lt;a href="http://www.corememory.org"&gt;Core Memory&lt;/a&gt;.&lt;br /&gt;&lt;hr&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_d3u4MHOJotc/STAY9CmIaKI/AAAAAAAAAHQ/pklIW3j8_M8/s1600-h/clouds4.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 158px;" src="http://3.bp.blogspot.com/_d3u4MHOJotc/STAY9CmIaKI/AAAAAAAAAHQ/pklIW3j8_M8/s320/clouds4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273742600598743202" /&gt;&lt;/a&gt;&lt;br /&gt;An &lt;span style="font-style:italic;"&gt;entity&lt;/span&gt; is an instance of a data &lt;span style="font-style:italic;"&gt;model&lt;/span&gt;, analogous to a data record in a database table. &lt;br /&gt;&lt;br /&gt;When you store such a chunk of data, sometimes you need to locate it quickly, using a unique identifier. This is the entity's &lt;span style="font-style:italic;"&gt;key&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;Keys for data entities are typically unique relative to the data model. They are commonly hidden in a web page so that, when the user clicks something, the appropriate key is passed back to the server. This "passing of keys" (from the server, to the user, then back to the server) happens in any web application  that empowers the user to create many-to-one relationships on a web page -- for example, to create a &lt;a href="http://passingkeys.appspot.com/"&gt;list with items&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; (GAE) hosting environment provides a database with a difference: when created, each entity is assigned a key &lt;span style="font-style:italic;"&gt;universal&lt;/span&gt; to Google's "Big Table", guaranteed never to change, and guaranteed to be accessible only from &lt;span style="font-style:italic;"&gt;your&lt;/span&gt; GAE application.&lt;br /&gt;&lt;br /&gt;This implies an unusual approach to passing keys to the browser. When the webapp generates a web page the data choices can be hidden in the page, not with ID's generated on-the-fly, but with permanent, universal keys. There are clues on how to do this, mostly implied or embedded, scattered across the &lt;a href="http://groups.google.com/group/google-appengine"&gt;Google App Engine Group's discussion forum&lt;/a&gt;, the &lt;a href="http://appengine-cookbook.appspot.com"&gt;GAE cookbook&lt;/a&gt;, etc. But there are no simple, deployed examples. So I thought I would provide &lt;a href="http://passingkeys.appspot.com/"&gt;one&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Unfolding of an Example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_d3u4MHOJotc/SUBkmLjpTnI/AAAAAAAAAHw/Z-S975l65bE/s1600-h/Picture+32.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 135px; height: 142px;" src="http://4.bp.blogspot.com/_d3u4MHOJotc/SUBkmLjpTnI/AAAAAAAAAHw/Z-S975l65bE/s200/Picture+32.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5278329370378325618" /&gt;&lt;/a&gt; To present this, I'm explicitly introducing an ancient illustrative technique to the world of software development, one that I think is particularly pleasant, unusually effective and full of possibility: &lt;span style="font-style:italic;"&gt;the unfolding of a program&lt;/span&gt;. It's a &lt;span style="font-style:italic;"&gt;polished sequence&lt;/span&gt; of stepwise software development. This is rather different than a walk-through of finished code. You may have seen it before in &lt;span style="font-style:italic;"&gt;public programming&lt;/span&gt; performances ... in fact, Google &lt;a href="http://www.youtube.com/watch?v=tcbpTQXNwac"&gt;introduced GAE&lt;/a&gt; with just such a performance, which I'll analyze in a separate paper.&lt;br /&gt;&lt;br /&gt;For the moment, let's think of a program as a living organism. &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_d3u4MHOJotc/SUBk2XNY20I/AAAAAAAAAH4/dhq3lcNwMNY/s1600-h/Picture+33.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 145px; height: 142px;" src="http://4.bp.blogspot.com/_d3u4MHOJotc/SUBk2XNY20I/AAAAAAAAAH4/dhq3lcNwMNY/s200/Picture+33.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5278329648384105282" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;During an organism's development, its structure and shape changes, moving from very simple to very complex. We marvel at nature's ability to maintain a coherent morphology amidst this massive engineering project. Amazingly, the elegant developmental sequences we see in nature, which generate such robust and complex mechanisms, are very flexible and adaptive. Living things tap a superb library of transformative solutions and methods. Since humans have only about 30,000 genes, life somehow creates robust, unique people from something analogous to 30,000 small functions. The Linux Kernal has about 10 million lines of code. We need to pay &lt;span style="font-style:italic;"&gt;much&lt;/span&gt; closer attention to nature.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_d3u4MHOJotc/SUBlDa_mlJI/AAAAAAAAAIA/8IHJ6TLH7uc/s1600-h/Picture+34.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 152px; height: 143px;" src="http://2.bp.blogspot.com/_d3u4MHOJotc/SUBlDa_mlJI/AAAAAAAAAIA/8IHJ6TLH7uc/s200/Picture+34.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5278329872738325650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you watch this gradual, incremental growth, you'll see difficult engineering problems overcome fluidly, simply, at each stage, at all scales. A great deal of &lt;span style="font-style:italic;"&gt;ad hoc&lt;/span&gt; adaptation is going on, adaptations synthesized from available information, used in a persistent, continuously &lt;i&gt;balanced&lt;/i&gt; approach to tackling the emergence of the &lt;i&gt;entire&lt;/i&gt; organism, not just tiny parts of it. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_d3u4MHOJotc/SUBlNoxwkDI/AAAAAAAAAII/gg3tytmaBfo/s1600-h/Picture+35.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 192px; height: 186px;" src="http://1.bp.blogspot.com/_d3u4MHOJotc/SUBlNoxwkDI/AAAAAAAAAII/gg3tytmaBfo/s200/Picture+35.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5278330048237047858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This holistic, stepwise approach to growth can be seen as following, or borrowing from, many &lt;i&gt;sequences&lt;/i&gt; of steps. Each step creates a morphological &lt;i&gt;differentiation&lt;/i&gt;, building upon the previous step, providing the context for the next. Surprisingly, although the number of sequences borrowed by a developing organism is vast, the number of differentiations is not. A human being develops in approximately 50 cell divisions, for example.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_d3u4MHOJotc/SUBlXlmM9mI/AAAAAAAAAIQ/cD3EbqO6O_Y/s1600-h/Picture+36.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 176px; height: 200px;" src="http://1.bp.blogspot.com/_d3u4MHOJotc/SUBlXlmM9mI/AAAAAAAAAIQ/cD3EbqO6O_Y/s200/Picture+36.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5278330219181962850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Assuming that programmers are called &lt;span style="font-style:italic;"&gt;developers&lt;/span&gt; because they engage in something strongly akin to this kind of &lt;span style="font-style:italic;"&gt;development&lt;/span&gt;, it's unfortunate that one of the least explored areas in programming is the study of the steps and sequences we use. When we decide to change code, at &lt;span style="font-style:italic;"&gt;that&lt;/span&gt; moment, &lt;i&gt;what&lt;/i&gt; are we doing? What are the problems, and what is our resolution? And &lt;span style="font-style:italic;"&gt;where&lt;/span&gt; are we going? Clearly it would be useful to pass these steps and sequences around, among ourselves, for the sake of improving our discipline. The study of &lt;span style="font-style:italic;"&gt;developmental programming&lt;/span&gt; could provide a quicker, more efficient and effective absorption of new contexts, in the fast-changing world of engineering. Sequences could provide another tool for Open Source computer science.&lt;br /&gt;&lt;br /&gt;If all this talk seems redolent of Design Patterns, there's a reason. The notion to identify sequences of steps that humans can take, to build complex coherent systems, comes from Christopher Alexander, whose practical architectural philosphy inspired the computing movement to mine patterns, and pattern languages. Research by Alexander and myself in the 1990's indicated, among many other things, that people take from a sequence whatever they need, absorbing information about dependencies, and borrowing solutions, and sensibilities, very like a developing organism making use of its genome.&lt;br /&gt;&lt;br /&gt;I believe that polished sequences are a complement to patterns and refactoring ... after you've refactored towards various patterns, you tend to think: "if only I'd known about A! At this point I would have done A instead of B" or "Y turned into a huge time-wasting problem later on. I'm sure someone else has run into this." &lt;br /&gt;&lt;br /&gt;Sequences give you the opportunity to save vast numbers of people from the frustration with poor solutions, and teh difficult path to rediscovery of an already known solution. Sequences can make us more effective, and help us to produce quality work more easily and more often.&lt;br /&gt;&lt;br /&gt;So, to our example. I hope this new approach is useful, and that the sequence itself provides solutions large and small, from which you can borrow.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Preliminary Step: Scope and Environment&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To get started, note that I'm not supplanting the steps found within the &lt;a href="http://code.google.com/appengine/docs/gettingstarted/"&gt;Google App Engine Getting Started&lt;/a&gt; tutorial, which is still the only coherent tutorial for Google App Engine development. If you're making use of my sequence, below, I assume that you're already running the development environment, based on instructions in the GAE tutorial. &lt;br /&gt;&lt;br /&gt;Again I'm focussed on &lt;span style="font-style:italic;"&gt;simply passing keys&lt;/span&gt;. This sequence will &lt;i&gt;not&lt;/i&gt; develop code for editing, ownership, user authentication, sessions, sorting, timestamps, AJAX, exception handling, CSS, backups or any number of otherwise perfectly reasonable and necessary features. But, clearly, those tasks too can be broken into small sequences, "snippets" if you will, which could be applied in an additive fashion to any application derived from this article.&lt;br /&gt;&lt;br /&gt;In this example I'm also using a very simple subset of Python, free of 'dunder' methods, and avoiding the &lt;a href="http://code.google.com/p/google-app-engine-django/"&gt;Django helper&lt;/a&gt;. I want to limit the number of technical features I'm describing here, while allowing as broad a swath of programmers as possible to read it. Similar limits were placed on the tutorials produced by Google.&lt;br /&gt;&lt;br /&gt;We'll call this List-Item sample application "Passing Keys", or "passingkeys" to GAE. It's hosted at &lt;a href="http://passingkeys.appspot.com"&gt;passingkeys.appspot.com&lt;/a&gt;, with links to the source. The primary Python module is &lt;span style="font-style:italic;"&gt;passingkeys.py&lt;/span&gt; .&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 1: Using purpose to shape the persistent data models&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My &lt;span style="font-style:italic;"&gt;first&lt;/span&gt; step directly reflects my &lt;span style="font-style:italic;"&gt;main&lt;/span&gt; goal.&lt;br /&gt;&lt;br /&gt;What do I want to do with this app? I want to create &lt;span style="font-style:italic;"&gt;Lists&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;Items&lt;/span&gt;. Since I know something about the GAE application space, there's no harm in using a little code to start. In fact, it immediately gives the reader some understanding of GAE. &lt;span style="font-style:italic;"&gt;Concrete&lt;/span&gt; implementation is &lt;span style="font-style:italic;"&gt;not&lt;/span&gt; taboo in the world of generative sequences: after all, information critical to a developing organism is conveyed through &lt;span style="font-style:italic;"&gt;real&lt;/span&gt; molecules. &lt;br /&gt;&lt;br /&gt;So, in &lt;span style="font-style:italic;"&gt;passingkeys.py&lt;/span&gt;, let's define &lt;span style="font-style:italic;"&gt;List&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;Item&lt;/span&gt;, two different Datastore models derived from the db class ... db is a Google App Engine wrapper for the Datastore API, which reads and writes from Google's Big Table, or its simulation in the development environment on your own machine.&lt;br /&gt;&lt;br /&gt;Note that the relationship between &lt;span style="font-style:italic;"&gt;List&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;Item&lt;/span&gt; is made explicit by Item's "&lt;span style="font-weight:bold;"&gt;ReferenceProperty (List)&lt;/span&gt;" declaration. We will assign to Item's &lt;span style="font-style:italic;"&gt;list_key&lt;/span&gt; the associated &lt;span style="font-style:italic;"&gt;List&lt;/span&gt; instance, when the time comes.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;class List(db.Model):&lt;br /&gt;  name = db.StringProperty(multiline=True)&lt;br /&gt;&lt;br /&gt;class Item(db.Model):&lt;br /&gt;  list_key = db.ReferenceProperty(List)&lt;br /&gt;  name = db.StringProperty(multiline=True)&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note: if you are using these steps to guide the development of a different application, it's good to keep data models that are understood separate from your exploratory models.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 2: Functional Centers and the First Bridge&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In passingkeys.py, we'll define the three clumps of code that I'll call &lt;span style="font-style:italic;"&gt;functional centers&lt;/span&gt;. They reflecting the three primary &lt;span style="font-style:italic;"&gt;centers of activity&lt;/span&gt; that I foresee in this app. These aren't classes yet. But this outline bridges the gap between, on the one hand, the user's sense of real activity, and on the other hand, web technology (GETs, POSTs, forms rendering HTML) and the supporting classes and methods.&lt;br /&gt;&lt;br /&gt;&lt;div style="padding:20px;border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;br /&gt;The Home Page: &lt;br /&gt;* get: displays the current lists and items&lt;br /&gt;* render: called by all other functions to render a version of the home page&lt;br /&gt;&lt;br /&gt;Creating Lists: &lt;br /&gt;* get: renders the home page with a List form&lt;br /&gt;* post: handles the CGI POST to create a List&lt;br /&gt;&lt;br /&gt;Creating Items:&lt;br /&gt;* get: renders the home page with an Item form&lt;br /&gt;* post: handles the CGI POST to create an Item&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 3: The Class and Method Bridge&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I associated &lt;span style="font-weight:bold;"&gt;render&lt;/span&gt; above with the home page. But, when I step over the next bridge, to a &lt;span style="font-style:italic;"&gt;class and method outline&lt;/span&gt;, Python's object idiosyncrasies kick in. 'Class methods' are not normal in Python, so &lt;i&gt;render&lt;/i&gt; needs to be an isolated function definition. Hence, my &lt;span style="font-style:italic;"&gt;class and method outline&lt;/span&gt; is:&lt;br /&gt; &lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;def render&lt;br /&gt;   # renders home page&lt;br /&gt;&lt;br /&gt;# handlers:&lt;br /&gt;class HomePage&lt;br /&gt;  def get&lt;br /&gt;      # returns render's output&lt;br /&gt;&lt;br /&gt;class CreateList&lt;br /&gt;  def get&lt;br /&gt;     # calls render with List form&lt;br /&gt;  def post&lt;br /&gt;     # creates a List&lt;br /&gt;&lt;br /&gt;class CreateItem&lt;br /&gt;  def get&lt;br /&gt;     # calls render with Item form&lt;br /&gt;  def post&lt;br /&gt;     # creates an Item&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 4: Encode the Handler Shells; Outline Rendering&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;Let's make the class and method outline more rigid, 'hardening' the shells of both.&lt;br /&gt;&lt;br /&gt;Some might complain that this approach is too top-down, that I'm not following an &lt;span style="font-style:italic;"&gt;end-to-end&lt;/span&gt; incremental methodology here. But, this &lt;span style="font-style:italic;"&gt;is&lt;/span&gt; runnable code. Over the decades, programming languages have shifted towards pseudocode, so that we can ease our way through these early differentiating stages more naturally. The previous steps &lt;span style="font-style:italic;"&gt;could&lt;/span&gt; be end-to-end, and runnable, if the language and environment shifted a little further in this direction. And if it included higher-level descriptions for web-page pathways. I find the conflicting environmental support for people who've done the same thing many times, and people who are exploring the environment for the first time, to be unnecessary. With open-source sequences, these incongruities would resolve themselves, with better development environments.&lt;br /&gt;&lt;br /&gt;There's a hidden assumption in what follows -- it's in my mind, so I might as well spell it out. For simplicity, I'll use &lt;span style="font-style:italic;"&gt;one&lt;/span&gt; Django template, which I'll name &lt;i&gt;index.html&lt;/i&gt;, to create the HTML presented to the user. The template will be populated with &lt;span style="font-style:italic;"&gt;Item&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;List&lt;/span&gt; data by my &lt;i&gt;render&lt;/i&gt; function, which in turn is passed a Python dictionary (a collection of name-value pairs). This dictionary also includes switches to turn the forms on and off.&lt;br /&gt;&lt;br /&gt;Here's an &lt;span style="font-style:italic;"&gt;implementation outline&lt;/span&gt; of the five handler methods + 1 render function:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;def render (template_values):&lt;br /&gt;   # put data in template_values&lt;br /&gt;   # call Django templating&lt;br /&gt;   # return results to calling handler&lt;br /&gt;&lt;br /&gt;class HomePage (webapp.RequestHandler):&lt;br /&gt;  def get (self):&lt;br /&gt;     # create vanilla home page&lt;br /&gt;     # by calling render&lt;br /&gt;&lt;br /&gt;class CreateList (webapp.RequestHandler):&lt;br /&gt;  def get (self):&lt;br /&gt;     # create list form&lt;br /&gt;     # by calling render&lt;br /&gt;&lt;br /&gt;  def post (self):&lt;br /&gt;     # insert data from list form&lt;br /&gt;     # redirect to home&lt;br /&gt;&lt;br /&gt;class CreateItem (webapp.RequestHandler):&lt;br /&gt;  def get (self, list_key):&lt;br /&gt;     # create item form with hidden list_key&lt;br /&gt;     # by calling render&lt;br /&gt;&lt;br /&gt;  def post (self):&lt;br /&gt;     # insert data from item form&lt;br /&gt;     # redirect to home&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I call my &lt;span style="font-weight:bold;"&gt;render&lt;/span&gt; function for GETs, and I redirect to &lt;span style="font-weight:bold;"&gt;home&lt;/span&gt; after POSTs. I could consistently call the render function, or with a session layer I could consistently redirect. I'm just trying to reduce overhead, for this example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 5: Directing URL Regexes to Handlers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As per GAE's default &lt;span style="font-style:italic;"&gt;webapp&lt;/span&gt; WSGI framework, there's a mapping, at the end of passingkeys.py, between our defined URL regex's and our request handlers. So the end of every main web application module in GAE-land looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;application = webapp.WSGIApplication(&lt;br /&gt;                                     [('/', HomePage),&lt;br /&gt;                                        ('/list_form/', CreateList),&lt;br /&gt;                                        ('/create_list/', CreateList),&lt;br /&gt;                                        ('/item_form/(.*)/', CreateItem,&lt;br /&gt;                                        ('/create_item/', CreateItem)],&lt;br /&gt;                                     debug=True)&lt;br /&gt;&lt;br /&gt;def main():&lt;br /&gt;  run_wsgi_app(application)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;  main()&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The critically important detail here, relative to passing keys in a Python/GAE implementation, is the "(.*)" in the regex, which passes the contents of that string (a key coming back from the user) as an argument to &lt;span style="font-style:italic;"&gt;CreateItem's&lt;/span&gt; CGI GET handler,  which we call "list_key" inside &lt;span style="font-style:italic;"&gt;CreateItem.get&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 6: Encode Template Rendering&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Django template index.html will be rendered by my &lt;span style="font-weight:bold;"&gt;render&lt;/span&gt; function, which initially just looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;   def render (template_values):&lt;br /&gt;         # to do: add data to template_values&lt;br /&gt;        path = os.path.join(os.path.dirname(__file__), 'index.html')&lt;br /&gt;        self.response.out.write(template.render(path, template_values))&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 7: Encode Template Values for Create Get Methods&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;CreateList and CreateItem's GET handlers will pass a Python dictionary structure, with switches and a key, to my &lt;span style="font-style:italic;"&gt;render&lt;/span&gt; :&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;class CreateList (webapp.RequestHandler):&lt;br /&gt;  def get (self):&lt;br /&gt;     template_values = {&lt;br /&gt;        'ListForm': 1&lt;br /&gt;     }&lt;br /&gt;     self.response.out.write (render(template_values))&lt;br /&gt;&lt;br /&gt;class CreateItem (webapp.RequestHandler):&lt;br /&gt;  def get (self, list_key):&lt;br /&gt;     template_values = {&lt;br /&gt;        'item_form': 1,&lt;br /&gt;        'list_key': list_key&lt;br /&gt;     }&lt;br /&gt;     self.response.out.write (render(template_values))&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 8: Template Logic Outline&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For &lt;span style="font-style:italic;"&gt;developmental balance&lt;/span&gt;, I'm compelled now to complete our &lt;span style="font-style:italic;"&gt;end-to-end&lt;/span&gt; infrastructure here, with a quick cut at our Django template index.html, based on the assumptions so far:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;title&amp;gt;Passing Keys&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" &amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;a href="/"&amp;gt;&amp;lt;font size="+3"&amp;gt;&amp;lt;b&amp;gt;Passing Keys&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt; &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;{% if list_form %}&lt;br /&gt;   {# list_form #}&lt;br /&gt;{% else %}&lt;br /&gt;  &amp;lt;a href="/list_form/"&amp;gt;Create a List&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;{% endif %}&lt;br /&gt;{% for list in lists %}&lt;br /&gt;   {{ list.name }}&amp;lt;br&amp;gt;&lt;br /&gt;   {% for item in list.items %}&lt;br /&gt;      {{ item.name }} &lt;br /&gt;   {% endfor %}&lt;br /&gt;   {% if item_form %}&lt;br /&gt;      {% ifequal list.key list_key %}&lt;br /&gt;         {# item form #}&lt;br /&gt;      {% else %}&lt;br /&gt;        &amp;lt;a href="/item_form/{{ list.key }}/#form"&amp;gt;Create an item&amp;lt;/a&amp;gt;&lt;br /&gt;        &amp;lt;br&amp;gt;&lt;br /&gt;      {% endifequal %}&lt;br /&gt;   {% else %}&lt;br /&gt;         &amp;lt;a href="/item_form/{{ list.key }}/#form"&amp;gt;Create an item&amp;lt;/a&amp;gt;&lt;br /&gt;   {% endif %}&lt;br /&gt;{% endfor %}&lt;br /&gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;[Note that the end-to-end implementation cycle has started. Here, I start with the "Create" links. People tend to follow this cycle, this mini sequence, as a reality check during live webapp development: create links -&gt; create form -&gt; entity storage -&gt; render data. It's a very natural cycle, and so common that, if you watch development in time-lapse, it'll make you dizzy. You can see it in &lt;span style="font-style:italic;"&gt;public programming&lt;/span&gt; events like the &lt;a href="http://www.youtube.com/watch?v=tcbpTQXNwac"&gt;Google App Engine Introduction.&lt;/a&gt; I did it too, and it's reflected here. It's useful both in exploratory development and recapitulation.]&lt;br /&gt;&lt;br /&gt;What did I know at this "template logical outline" stage? With an evangelical passion for the Model-View-Controller pattern, Django templates attempt to force logical constraints on the developer, literally, by forcing as much logic as possible &lt;span style="font-style:italic;"&gt;out&lt;/span&gt; of the template. The result is a few extra conditional tags here and there -- for example, a test for &lt;span style="font-weight:bold;"&gt;item_form&lt;/span&gt; and a separate "equal" test for the desired &lt;span style="font-weight:bold;"&gt;list_key&lt;/span&gt;, resulting in a duplicate "Create an item" link in the template.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 9: Major "Create" Pathway&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Next I need to generate the List form, when the user clicks the "Create a List" link. Here's &lt;span style="font-weight:bold;"&gt;CreateList.get&lt;/span&gt; again, unchanged:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;class CreateList(webapp.RequestHandler):&lt;br /&gt;  def get(self):&lt;br /&gt;     template_values = {&lt;br /&gt;        'list_form': 1&lt;br /&gt;     }&lt;br /&gt;     self.response.out.write(render(template_values))&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;... and the matching form inside the template, turned on by the &lt;span style="font-style:italic;"&gt;list_form&lt;/span&gt; switch:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;{% if list_form %}&lt;br /&gt;  &amp;lt;form action="/create_list/" method="post"&amp;gt;&lt;br /&gt;    &amp;lt;textarea  style="background:#eeee00" name="name" rows=1 cols=33&amp;gt;&lt;br /&gt;    &amp;lt;/textarea&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;    &amp;lt;span align="left"&amp;gt;&lt;br /&gt;       &amp;lt;input type="Submit" name="button" value="Create list"&amp;gt;&lt;br /&gt;    &amp;lt;/span&amp;gt;&lt;br /&gt;    &amp;lt;span style="padding-left:138px"&amp;gt;&lt;br /&gt;       &amp;lt;a href="/"&amp;gt;cancel&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;    &amp;lt;br&amp;gt;&lt;br /&gt;  &amp;lt;/form&amp;gt;&lt;br /&gt;{% else %}&lt;br /&gt;  &amp;lt;br&amp;gt;&amp;nbsp;&amp;lt;a href="/list_form/"&amp;gt;Create a List&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;{% endif %}&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Then, I need &lt;span style="font-weight:bold;"&gt;CreateList.post&lt;/span&gt; to receive this POST, and create a list:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;  def post(self):&lt;br /&gt;    list = List()&lt;br /&gt;&lt;br /&gt;    list.name = self.request.get('name')&lt;br /&gt;    list.put()&lt;br /&gt;&lt;br /&gt;    self.redirect("/")&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 10: Bundling for a Template&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And then I need to display the list itself. I already have an idea for displaying items, so I'll write the code for rendering in one try.&lt;br /&gt;&lt;br /&gt;Which brings us to the biggest consequence of the Django template philosophy, at this stage -- our function &lt;span style="font-weight:bold;"&gt;render&lt;/span&gt; needs to pre-package a &lt;span style="font-style:italic;"&gt;new&lt;/span&gt; structure, to pass to the Django template rendering system. This is the used by the "{% for list in lists %}" and "{% for item in list.items %}" template tags in my &lt;span style="font-weight:bold;"&gt;index.html&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;To do this, render needs to fetch Lists and Items from the datastore and create a kind of &lt;span style="font-style:italic;"&gt;populating payload&lt;/span&gt;, which I build as "new_lists" below, and rename as "lists" to pass it to the template, within the "template_values" dict structure:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;def render (template_values):&lt;br /&gt;   lists = db.GqlQuery("SELECT * FROM List")&lt;br /&gt;&lt;br /&gt;  new_lists = []&lt;br /&gt;  for list in lists:&lt;br /&gt;     items = db.GqlQuery("SELECT * FROM Item Where list_key = :1",&lt;br /&gt;                                            list.key())&lt;br /&gt;&lt;br /&gt;     new_list = {&lt;br /&gt;        'name': list.name,&lt;br /&gt;        'key': str(list.key()),&lt;br /&gt;        'items': items&lt;br /&gt;     }&lt;br /&gt;     new_lists.append(new_list)&lt;br /&gt;  &lt;br /&gt;  template_values['lists'] = new_lists&lt;br /&gt;&lt;br /&gt;  path = os.path.join(os.path.dirname(__file__), 'index.html')&lt;br /&gt;  return(template.render(path, template_values))&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;... which is unraveled by the logic in the index.html Django template.&lt;br /&gt;&lt;br /&gt;(Note the need to cast the list.key() to a string for the payload).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 11: Minor "Create" Pathway&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To demonstrate this, I'll need to GET an Item form, making sure it has the list key. Again, &lt;span style="font-style:italic;"&gt;CreateItem.get&lt;/span&gt;, unchanged:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;class CreateItem(webapp.RequestHandler):&lt;br /&gt;  def get(self, list_key):&lt;br /&gt;     template_values = {&lt;br /&gt;        'item_form': 1,&lt;br /&gt;        'list_key': list_key&lt;br /&gt;     }&lt;br /&gt;     self.response.out.write(render(template_values))&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;... and its matching template section:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;{% if item_form %}&lt;br /&gt;      {% ifequal list.key list_key %}&lt;br /&gt;        &amp;lt;a name="form"&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;        &amp;lt;form action="/create_item/" method="post"&amp;gt;&lt;br /&gt;          &amp;lt;span style="padding-left:15px"&amp;gt;&lt;br /&gt;             &amp;lt;textarea style="background:#eeee00" name="name" rows=1 cols=33&amp;gt;&lt;br /&gt;             &amp;lt;/textarea&gt;&amp;lt;br&amp;gt;&lt;br /&gt;          &amp;lt;/span&amp;gt;&lt;br /&gt;          &amp;lt;span style="padding-left:15px"&amp;gt; &lt;br /&gt;             &amp;lt;input type="Submit" name="button" value="Create item"&amp;gt;&lt;br /&gt;          &amp;lt;/span&amp;gt;&lt;br /&gt;          &amp;lt;span style="padding-left:130px"&amp;gt;&lt;br /&gt;             &amp;lt;a href="/"&amp;gt;cancel&amp;lt;/a&amp;gt;&lt;br /&gt;          &amp;lt;/span&amp;gt;&lt;br /&gt;          &amp;lt;br&amp;gt;&lt;br /&gt;          &amp;lt;input type="hidden" name="list_key" value="{{ list_key }}"&amp;gt;&lt;br /&gt;        &amp;lt;/form&amp;gt;&lt;br /&gt;      {% else %}&lt;br /&gt;        &amp;lt;br&amp;gt;&lt;br /&gt;        &amp;lt;span style="padding-left:15px"&amp;gt;&lt;br /&gt;           &amp;lt;a href="/item_form/{{ list.key }}/#form"&amp;gt;Create an item&amp;lt;/a&amp;gt;&lt;br /&gt;        &amp;lt;/span&amp;gt;&lt;br /&gt;        &amp;lt;br&gt;&amp;lt;br&amp;gt;&lt;br /&gt;      {% endifequal %}&lt;br /&gt;   {% else %}&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;We'll instantiate &lt;span style="font-style:italic;"&gt;Items&lt;/span&gt; in the &lt;span style="font-style:italic;"&gt;CreateItem.post&lt;/span&gt; handler:&lt;br /&gt;&lt;br /&gt;&lt;div style="border-width:1px;border-style:solid;border-color:#cccccc"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;  def post(self):&lt;br /&gt;    item = Item()&lt;br /&gt;&lt;br /&gt;    item.list_key = self.request.get('list_key') &lt;br /&gt;    item.name = self.request.get('name')&lt;br /&gt;    item.put()&lt;br /&gt;&lt;br /&gt;    self.redirect("/")&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's all. That's one sequence, of medium length.&lt;br /&gt;&lt;br /&gt;The application runs on GAE &lt;a href="http://passingkeys.appspot.com"&gt;here&lt;/a&gt;, along with the final versions of &lt;a href="http://passingkeys.appspot.com/passingkeys.py.txt"&gt;passingkeys.py&lt;/a&gt;, &lt;a href="http://passingkeys.appspot.com/index.html.txt"&gt;index.html&lt;/a&gt;, and the &lt;a href="http://passingkeys.appspot.com/app.yaml.txt"&gt;app.yaml&lt;/a&gt; control file (which includes a mapping for these static source files).&lt;br /&gt;&lt;br /&gt;This sequence cannot represent the intentions of the builders of Python, Django or the GAE implementation. It is only the story of my resolutions to my problems. It will only let you understand what I've done. But, you may find that some part is useful for your application.&lt;br /&gt;&lt;br /&gt;Of course, there are many problems with this small sequence. It's not perfect. However, I believe that many such sequences, ironed-out, polished and improved, can serve as inspiring programming resources. This practical, introspective approach may guide us to a future of smoother software development, for more complex and coherent systems. It might also shape the future of tools and languages to support good engineering and design.&lt;br /&gt;&lt;br /&gt;We only need to take nature's achievements seriously.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1856743739898714601-3515756750537102015?l=workingclouds.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://workingclouds.blogspot.com/feeds/3515756750537102015/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1856743739898714601&amp;postID=3515756750537102015' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/3515756750537102015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/3515756750537102015'/><link rel='alternate' type='text/html' href='http://workingclouds.blogspot.com/2008/11/passing-keys.html' title='Passing Keys'/><author><name>Greg Bryant</name><uri>http://www.blogger.com/profile/13408526593029789018</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_d3u4MHOJotc/STAY9CmIaKI/AAAAAAAAAHQ/pklIW3j8_M8/s72-c/clouds4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1856743739898714601.post-7808094045804002421</id><published>2008-11-01T14:07:00.000-07:00</published><updated>2010-01-16T14:19:18.320-08:00</updated><title type='text'>Google App Engine: local debugging and logging</title><content type='html'>Google provides &lt;a href="http://code.google.com/appengine/articles/logging.html"&gt;instructions&lt;/a&gt; for using the Python logging module for debugging, and logging, in Google App Engine's Python environment.&lt;br /&gt;&lt;br /&gt;The document describes fetching log lines from the actual cloud itself. Unfortunately, I can't find references on doing this locally, in my development environment: the local administration console is not as full-featured as the cloud one. &lt;br /&gt;&lt;br /&gt;Luckily, I found this flag (--debug) which makes the logging module messages appear in my terminal output:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;clear; dev_appserver.py --clear_datastore --debug .&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(I clear the terminal screen so I can freshly search on keywords to find a particular log line.)&lt;br /&gt;&lt;br /&gt;This works pretty well. And it's essential for debugging a server/CGI application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1856743739898714601-7808094045804002421?l=workingclouds.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://workingclouds.blogspot.com/feeds/7808094045804002421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1856743739898714601&amp;postID=7808094045804002421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/7808094045804002421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/7808094045804002421'/><link rel='alternate' type='text/html' href='http://workingclouds.blogspot.com/2008/11/google-app-engine-local-debugging-and.html' title='Google App Engine: local debugging and logging'/><author><name>Greg Bryant</name><uri>http://www.blogger.com/profile/13408526593029789018</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1856743739898714601.post-5283916099457296296</id><published>2008-10-31T23:01:00.000-07:00</published><updated>2008-12-03T11:29:56.966-08:00</updated><title type='text'>Google App Engine without the App</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_d3u4MHOJotc/SQv2UHulPVI/AAAAAAAAAHI/9izitPSUs4g/s1600-h/index_r3_c3.gif"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 85px; height: 40px;" src="http://3.bp.blogspot.com/_d3u4MHOJotc/SQv2UHulPVI/AAAAAAAAAHI/9izitPSUs4g/s200/index_r3_c3.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5263571415044799826" /&gt;&lt;/a&gt;&lt;br /&gt;Say you have a legacy &lt;span style="font-weight:bold;"&gt;static&lt;/span&gt; website -- just HTML and images -- and you'd like to host it on &lt;a href="http://www.appspot.com"&gt;Google App Engine&lt;/a&gt; while you ponder the direction you'd like to take it in the future.&lt;br /&gt;&lt;br /&gt;Well, in a way, you're lucky: it's &lt;span style="font-weight:bold;"&gt;much&lt;/span&gt; easier to port a &lt;span style="font-style:italic;"&gt;static&lt;/span&gt; site to GAE, than it is to port a web app (we used to call these "dynamic" sites ... remember?) Unless you've been a Python web developer, you'll be starting from scratch if you're developing web apps for GAE.&lt;br /&gt;&lt;br /&gt;But how do you port an &lt;span style="font-weight:bold;"&gt;entirely&lt;/span&gt; static site? Luckily, my wife, &lt;a href="http://www.olgallery.com"&gt;Olga Volchkova&lt;/a&gt; asked me to do just this. She wanted to see her old website, live. She built this very lovely hand-painted Fireworks/Dreamweaver site in late 2000, which we first released in early 2001, and which she hasn't touched since 2002. It &lt;span style="font-style:italic;"&gt;looks&lt;/span&gt; very 2001 -- well, very much like &lt;span style="font-style:italic;"&gt;her&lt;/span&gt; work in 2001, heavily influenced by the Golden Age of Russian animation from 1965 to 1985, best represented by &lt;a href="http://en.wikipedia.org/wiki/Yuri_Norstein"&gt;Yuri Norstein&lt;/a&gt;'s wonderfully gentle short films, like &lt;a href="http://www.youtube.com/watch?v=JZS1fLK4DYM"&gt;Hedgehog in the Fog&lt;/a&gt; -- and happily there wasn't a bit of code involved!&lt;br /&gt;&lt;br /&gt;The only problem was the file quota: 1000 files is the limit for GAE. Macromedia Fireworks was profligate with files, dividing, in one case, a single page of hers into over 400! I culled that page for now ... I'll upload it as another project (Google gives you five GAE projects per cell phone number) some other time.&lt;br /&gt;&lt;br /&gt;So, here's what an app.yaml file for a bunch of static html, htm, gif and jpg files looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;application: olgallerycom&lt;br /&gt;version: 1&lt;br /&gt;runtime: python&lt;br /&gt;api_version: 1&lt;br /&gt;&lt;br /&gt;handlers:&lt;br /&gt;&lt;br /&gt;- url: /&lt;br /&gt;  static_files: index.html&lt;br /&gt;  upload: index.html&lt;br /&gt;  &lt;br /&gt;- url: /(.*)&lt;br /&gt;  static_files: \1&lt;br /&gt;  upload: (.*)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;No Python in sight. &lt;br /&gt;&lt;br /&gt;I use the static_files feature of app.yaml ... it is more flexible, in a sense, than static_dir. I eliminated the Python, because the collection of files already had a working structure, which I decided to preserve. It was easier than wrapping the file fetches in code and rearranging the directories.&lt;br /&gt;&lt;br /&gt;This is fast and easy, and recommended if you need to get a legacy site up quickly. You can see the resulting sweet, gentle &lt;a href="http://www.olgallery.com"&gt;legacy site of Olga Volchkova&lt;/a&gt;, running on GAE.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1856743739898714601-5283916099457296296?l=workingclouds.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://workingclouds.blogspot.com/feeds/5283916099457296296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1856743739898714601&amp;postID=5283916099457296296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/5283916099457296296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/5283916099457296296'/><link rel='alternate' type='text/html' href='http://workingclouds.blogspot.com/2008/10/google-app-engine-without-app.html' title='Google App Engine without the App'/><author><name>Greg Bryant</name><uri>http://www.blogger.com/profile/13408526593029789018</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_d3u4MHOJotc/SQv2UHulPVI/AAAAAAAAAHI/9izitPSUs4g/s72-c/index_r3_c3.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1856743739898714601.post-8686602652142976784</id><published>2008-09-30T18:58:00.000-07:00</published><updated>2008-09-30T19:50:10.073-07:00</updated><title type='text'>Little secret: dev_appserver is_required</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_d3u4MHOJotc/SOLhGDL_v0I/AAAAAAAAAHA/iuuasKE76Zw/s1600-h/lightning.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_d3u4MHOJotc/SOLhGDL_v0I/AAAAAAAAAHA/iuuasKE76Zw/s200/lightning.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5252007609518505794" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br&gt;If you &lt;span style="font-weight:bold;"&gt;do&lt;/span&gt; skip around and rearrange the steps of the tutorials for Google App Engine, one thing you may &lt;span style="font-weight:bold;"&gt;try&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;/span&gt; to do, is continually, incrementally, &lt;span style="font-style:italic;"&gt;directly&lt;span style="font-weight:bold;"&gt;&lt;/span&gt;&lt;/span&gt; upload to Google, using &lt;span style="font-style:italic;"&gt;appcfg.py update&lt;span style="font-weight:bold;"&gt;&lt;/span&gt;&lt;/span&gt; ...&lt;br /&gt;&lt;br /&gt;Unfortunately, this won't work. If you use GQL and the Datastore API, you'll find that you &lt;span style="font-style:italic;"&gt;need&lt;span style="font-weight:bold;"&gt;&lt;/span&gt;&lt;/span&gt; to run the local development server &lt;span style="font-style:italic;"&gt;dev_appserver.py&lt;span style="font-weight:bold;"&gt;&lt;/span&gt;&lt;/span&gt; before deploying ... the dev server creates an &lt;span style="font-weight:bold;"&gt;index.yaml&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;/span&gt; file, essentially mapping your db model and its use to Big Table. This gets deployed with your application. So, skipping this step (at least for most applications, which use the db) is not an option.&lt;br /&gt;&lt;br /&gt;If you don't run the local dev_appserver, you'll get error messages from Google's servers when you run your webapp, like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "/base/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 499, in __call__&lt;br /&gt;    handler.get(*groups)&lt;br /&gt;  File "/base/data/home/apps/2splice/1.31/main.py", line 20, in get&lt;br /&gt;    for greeting in greetings:&lt;br /&gt;  File "/base/python_lib/versions/1/google/appengine/ext/db/__init__.py", line 1257, in __iter__&lt;br /&gt;    return self.run()&lt;br /&gt;  File "/base/python_lib/versions/1/google/appengine/ext/db/__init__.py", line 1589, in run&lt;br /&gt;    query_run = self._proto_query.Run(*self._args, **self._kwds)&lt;br /&gt;  File "/base/python_lib/versions/1/google/appengine/ext/gql/__init__.py", line 581, in Run&lt;br /&gt;    res = bind_results.Get(self.__limit, offset)&lt;br /&gt;  File "/base/python_lib/versions/1/google/appengine/api/datastore.py", line 938, in Get&lt;br /&gt;    return self._Run(limit, offset)._Next(limit)&lt;br /&gt;  File "/base/python_lib/versions/1/google/appengine/api/datastore.py", line 887, in _Run&lt;br /&gt;    str(exc) + '\nThis query needs this index:\n' + yaml)&lt;br /&gt;NeedIndexError: no matching index found.&lt;br /&gt;This query needs this index:&lt;br /&gt;- kind: Greeting&lt;br /&gt;  properties:&lt;br /&gt;  - name: date&lt;br /&gt;    direction: desc&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1856743739898714601-8686602652142976784?l=workingclouds.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://workingclouds.blogspot.com/feeds/8686602652142976784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1856743739898714601&amp;postID=8686602652142976784' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/8686602652142976784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/8686602652142976784'/><link rel='alternate' type='text/html' href='http://workingclouds.blogspot.com/2008/09/devappserver-isrequired.html' title='Little secret: dev_appserver is_required'/><author><name>Greg Bryant</name><uri>http://www.blogger.com/profile/13408526593029789018</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_d3u4MHOJotc/SOLhGDL_v0I/AAAAAAAAAHA/iuuasKE76Zw/s72-c/lightning.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1856743739898714601.post-5982785392048691470</id><published>2008-09-21T22:23:00.000-07:00</published><updated>2009-09-11T10:53:04.237-07:00</updated><title type='text'>Google App Engine: quick-end-to-end</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_d3u4MHOJotc/SNdX6Qzda5I/AAAAAAAAAGA/gkSmsNjtn7k/s1600-h/Clouds.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_d3u4MHOJotc/SNdX6Qzda5I/AAAAAAAAAGA/gkSmsNjtn7k/s400/Clouds.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5248760549178436498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here's a breathless, running narration of a one-hour attempt to get App Engine serving a web application. &lt;br /&gt;&lt;br /&gt;A small complaint: the &lt;a href="http://code.google.com/appengine/docs/gettingstarted/"&gt;tutorials&lt;/a&gt; for Google App Engine are not geared towards getting a first &lt;span style="font-style:italic;"&gt;real&lt;/span&gt; webapp deployed quickly. They are, instead, intended to give a web developer a pretty complete survey of the infrastructure for web development. Unfortunately, this means you really need to dig around to understand how to fully deploy, say, "helloworld" to "helloworld.com". &lt;br /&gt;&lt;br /&gt;So, to address this deficit, here's an end-to-end, holistic version of the Google App Engine tutorial. I'm using a Macbook, running 10.4.11, and my domain name registrar is &lt;a href="http://www.networksolutions.com"&gt;Network Solutions&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;1) Gain registration-level control over the domain name: &lt;a href="http://www.networksolutions.com"&gt;networks solutions&lt;/a&gt;, &lt;a href="https://www.godaddy.com/"&gt;godaddy&lt;/a&gt;, &lt;a href="http://www.register.com/"&gt;register.com&lt;/a&gt;, etc.&lt;br /&gt;&lt;br /&gt;2) Sign up for free Standard Google Apps, using that domain, &lt;a href="https://www.google.com/a/"&gt;here&lt;/a&gt;. (Update: here's the current link directly to the &lt;a href="http://www.google.com/apps/intl/en/group/index.html"&gt;free Standard Google Apps edition&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;3) Log into  http://appengine.google.com/a/[your-domain-name].&lt;br /&gt;&lt;br /&gt;4) Follow the instructions to name your app (after your-domain-name is easiest) ... you get an access code, for verification, on your cellphone.&lt;br /&gt;&lt;br /&gt;5) Install Python 2.5 on your local machine, from &lt;a href="http://www.python.org/"&gt;here&lt;/a&gt;. No earlier version will work, but installers are available for all platforms. Note that after installation, on a Mac, you'll need to use Get Info on any python file, to make all python scripts open with the 2.5 Python launcher (which was just installed in your Applications directory). &lt;br /&gt;&lt;br /&gt;6) Download the Google App Engine Launcher for your local machine, &lt;a href="http://code.google.com/appengine/downloads.html"&gt;here&lt;/a&gt;. Copy it to your Applications directory before launching it. Launch and install. On the Mac you'll need to restart your shell (or terminal) to pick up the new python.&lt;br /&gt;&lt;br /&gt;7) Then, from &lt;a href="http://code.google.com/appengine/docs/gettingstarted/helloworld.html"&gt;the first half of the third page of the tutorial&lt;/a&gt;:&lt;br /&gt;a) create a &lt;span style="font-weight:bold;"&gt;your-app-name&lt;/span&gt; directory&lt;br /&gt;b) within that directory, make an app.yaml file, as described above, changing 'helloworld' to &lt;span style="font-weight:bold;"&gt;your-app-name&lt;/span&gt; within the file.&lt;br /&gt;c) borrow the "helloworld" app itself above, and copy it into a &lt;span style="font-weight:bold;"&gt;your-app-name.py&lt;/span&gt; file.&lt;br /&gt;d) in the shell, &lt;span style="font-weight:bold;"&gt;cd&lt;/span&gt; to the parent of this directory&lt;br /&gt;e) upload / deploy your app with &lt;span style="font-weight:bold;"&gt;appcfg.py update your-app-name/&lt;/span&gt;&lt;br /&gt;f) appcfg will ask you for the email and password of your google app account.&lt;br /&gt;g) back on your appengine overview page (&lt;a href="http://appengine.google.com/"&gt;http://appengine.google.com/&lt;/a&gt;), you'll get a notice that an app was successfully deployed.&lt;br /&gt;&lt;br /&gt;8) On this page (&lt;a href="http://appengine.google.com/"&gt;http://appengine.google.com/&lt;/a&gt;) click the &lt;span style="font-weight:bold;"&gt;name&lt;/span&gt; of the app. This will bring you to your app engine app's &lt;span style="font-weight:bold;"&gt;dashboard&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;9) Click "versions". Follow the instructions for "add domain" ... you will need to prove the domain by signing up for Google Apps from here (The instructions on that page read: &lt;span style="font-weight:bold;"&gt;Changing a CNAME Record&lt;/span&gt;), and then come back to &lt;span style="font-weight:bold;"&gt;versions-&gt;add domain&lt;/span&gt;, type the domain name and click "add domain ..." so that ghs.google.com. will handle CNAME aliases from your registrar. &lt;br /&gt;&lt;br /&gt;10) Back at my registrar, I delete the A Record for www, and do an "advanced DNS" move: a CNAME alias for www, to ghs.google.com. This works, and my app is now hosted by google at the domain I want.&lt;br /&gt;&lt;br /&gt;8, 9 and 10 can be stumbled upon &lt;a href="http://www.google.com/support/a/bin/answer.py?hl=en&amp;answer=91080"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1856743739898714601-5982785392048691470?l=workingclouds.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://workingclouds.blogspot.com/feeds/5982785392048691470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1856743739898714601&amp;postID=5982785392048691470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/5982785392048691470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1856743739898714601/posts/default/5982785392048691470'/><link rel='alternate' type='text/html' href='http://workingclouds.blogspot.com/2008/09/google-app-engine-incapable-of-web-app.html' title='Google App Engine: quick-end-to-end'/><author><name>Greg Bryant</name><uri>http://www.blogger.com/profile/13408526593029789018</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_d3u4MHOJotc/SNdX6Qzda5I/AAAAAAAAAGA/gkSmsNjtn7k/s72-c/Clouds.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
