When are projects due? #infomgmtFAIL – This is why you never duplicate data. – Project 4 is Due To get it done in time you will need to work smart, cut corners, and adjust rapidly. – Use Rally's Burn-down charts to help you calibrate – Ask when >30mins of head-wall contact Asking is nice even if you figure it out yourself – It does NOT need to be a website/phone app/etc. Results > UX for project 4.
Prototype with Google App Engine Goal: Everyone gets to share one comment that is geotagged. Twitter-lite. Get set up: – – Everyone in your group!
Web services 101 Little "s" - bob Everything is an ACTION to a URL with some PARAMETERS – A "GET" to "/" with NO PARAMS – A "GET" to "/search" with ONE param (URL encoded) of q="Hello World" … – POSTS you can't just type in the browser bar, but are normally form submits. Nice way to divide action from browsing. – Have a URL + a payload of name/value pairs (mostly) Also PUT, DELETE and HEAD, but who cares…
Google Datastore Stuff you don't need to know – "Paxos algorithm" – "ancestor queries" – High availability, entity groups, bla bla bla Stuff you do need to know – A little SQL – Basic idea of data types
Build application = webapp.WSGIApplication([ ('/', MainPage) #,('/sign', Guestbook) ], debug=True) def main(): run_wsgi_app(application) # if __name__ == '__main__': main()
User Management class MainPage(webapp.RequestHandler): def get(self): user = users.get_current_user() if user: self.response.headers['Content-Type'] = 'text/plain' self.response.out.write('Hello, ' + user.nickname()) else: self.redirect(users.create_login_url(self.request.uri)) This is so much nicer than debating with the architect if your users should be indexed by address, or their user ID, or a unique 11 digit integer, or off their DB AUTO_INCREMENT ID, or… bla.
Knowing what was Posted def post(self): self.response.out.write(' You wrote: ') self.response.out.write( cgi.escape(self.request.get('content')) ) self.response.out.write(' ')
So what? Need to save it! class Tweet(db.Model): """Models an individual entry with an author, content, and date.""" author = db.UserProperty() content = db.StringProperty(multiline=True) date = db.DateTimeProperty(auto_now_add=True) …so nice not to be writing SQL create statements. And DB modeling. And all the other overhead. A prototyper could get spoiled with this…
How to show a page of HTML? Annoying way – self.response.out.write(""" … Better way: path = os.path.join(os.path.dirname(__file__), 'index.html') self.response.out.write(template.render(path, template_values)) And every key in template_values maps to {{ key }}
Actually Saving It # Still figuring this "parent" thing out. bhill def tweetbucket_key(): """Constructs a datastore key for tweet entities""" return db.Key.from_path('Tweets', 'default_tweetbucket') def post(self): new_tweet = Tweet(parent=tweetbucket_key()) if users.get_current_user(): new_tweet.author = users.get_current_user() new_tweet.content = self.request.get('content') new_tweet.put()
Get back what you put in class AllPosts(webapp.RequestHandler): def get(self): tweets = db.GqlQuery("SELECT * " "FROM Tweet " "WHERE ANCESTOR IS :1 " "ORDER BY date DESC LIMIT 100", tweetbucket_key()) result = [] # simple array for tweet in tweets: result.append({ 'author':tweet.author.nickname(), 'content':tweet.content, 'date':tweet.date.isoformat() }) # simple object appended to array content = simplejson.dumps(result) if callback: # JSON-P in 2 lines. content = cgi.escape(callback) +"(" + content + ")" self.response.headers.add_header('content-type', 'application/json', charset='utf-8') self.response.out.write(content)