A recent post and talk on twitter about host providers got me interested in building a blog using Google App Engine (GAE). It’s free to use and would eliminate having to pay for a hosting provider for a small site. My blog turned out like this jsoncharts. I’m pretty happy with it so far.
I got started with Python and GAE by reading the documentation and using the examples on the Google App Engine site. Then I used this article and framework for the base of my blog. The major changes I made were adding commenting and friendly URL’s. I can have URL’s like this (http://jsoncharts.appspot.com/blog/force-directed-graph-with-raphael) and comments on the articles (http://jsoncharts.appspot.com/blog/force-directed-graph-with-raphael#respond).
Adding friendly URL’s was easy enough. Following Bret Taylor’s example here is what my WSGIApplication instance looks like.
application = webapp.WSGIApplication(
[('/', FrontPageHandler),
('/tag/([^/]+)/*$', ArticlesByTagHandler),
('/date/(\d\d\d\d)-(\d\d)/?$', ArticlesForMonthHandler),
('/'+ defs.ARTICLE_URL_PATH +'/(\d+)/?$', SingleArticleHandler),
('/'+ defs.ARTICLE_URL_PATH +'/([^/]+)', SingleArticleHandlerBySlug),
('/archive/?$', ArchivePageHandler),
('/rss2/?$', RSSFeedHandler),
('/.*$', NotFoundPageHandler),
],
The following line routes incoming request to a class handler named “SingleArticleHandlerBySlug”.
('/'+ defs.ARTICLE_URL_PATH +'/([^/]+)', SingleArticleHandlerBySlug),
The handler looks like this:
class SingleArticleHandlerBySlug(AbstractPageHandler):
"""
Handles requests to display a single article, given its unique ID.
Handles nonexistent IDs.
"""
def get(self, slug):
article = Article.get_for_slug(slug)
comments = None
if article:
comments = Comment.get_all_by_articleId(article.id)
template = 'show-single-article.html'
articles = [article]
more = None
else:
template = 'not-found.html'
articles = []
self.response.out.write(self.render_articles(articles=articles,
request=self.request,
recent=self.get_recent(),
template_name=template,
comments=comments))
To add the commenting I had to create a new model class for storage. This was very simple.
class Comment(db.Model):
name = db.TextProperty()
email = db.TextProperty()
website = db.TextProperty()
body = db.TextProperty()
commented_when = db.DateTimeProperty(auto_now_add=True)
id = db.IntegerProperty()
articleId = db.IntegerProperty()
gravatar_url = db.TextProperty()
Then I added a few functions for finding and deleting and then added them in. I can’t remember ever doing something with storage this fast. I don’t miss SQL at all. GAE really hides all the storage implementation details for you. Here is an example of the functions used to access the data store.
@classmethod
def get_all(cls):
q = db.Query(Comment)
q.order('-commented_when')
return q.fetch(FETCH_THEM_ALL)
@classmethod
def get_all_by_articleId(cls, articleId):
q = db.Query(Comment)
q.filter('articleId = ', articleId)
q.order('-commented_when')
return q.fetch(FETCH_THEM_ALL)
That’s all it takes and you are ready to go.
Overall I was very impressed with the experience. In the future I’ll probably look into using Django’s form validation framework for comments and figure out how backups would work.
Post Related Links: