Blogging on App Engine, part 6: Comments and Search

This is part of a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

Today we're going to tackle two separate issues: Support for commenting on posts, and support for search. Commenting is fairly straightforward, so we'll deal with that first.


Rather than implement our own comments system, we're going to take advantage of an existing 'SaaS' commenting offering, Disqus. Disqus provides simple drop in Javascript powered comment support, and has, by now, a rather impressive feature set, incorporating support for various login schemes - their own, OpenID, facebook connect, twitter, and others - as well as advanced functionality like finding and displaying 'reactions' from social sites around the web along with comments from users.

Integrating disqus support is straightforward. Since some people might not want to use it, or might want to use an alternate system, however, we're going to use a new config setting to ensure we only enable it if it's wanted. Add the following to the bottom of

# To use disqus for comments, set this to the 'short name' of the disqus forum # created for the purpose. disqus_forum = None ...

Blogging on App Engine, part 5: Tagging

This is part of a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

Following on from our previous post, today we're going to deal with tagging. There are three components to adding tagging support to our blog:

  1. Adding tags to the model and the post/edit interface.
  2. Generating listing pages of posts with a given tag.
  3. Adding tags and links to the listing pages on individual posts.

We'll tackle these in order. First, adding tags to the model and to the add/edit post interface. Add the following property immediately after 'body' on the BlogPost class (in

tags = db.StringListProperty()

That's it. No, really. Thanks to our use of ModelForms, our admin interface now has support for adding and editing posts with tags. Try it, if you wish. One slight caveat: The interface expects tags to be separated by newlines, rather than by commas. That's something we could address with a custom widget, at a later stage.

Next, the listing pages. Nearly all the functionality required to generate listings of posts with a given tag is identical to that required to generate ...

Blogging on App Engine, part 4: Listings

This is part of a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

As you may have surmised from previous posts in the series, the 'static serving' approach we're using can lead to regenerating a lot of pages at once. For a long lived blog, with lots of history, regenerating the archive pages could take a significant amount of time - potentially long enough that we could run into the 30 second request deadline when updating or adding a post. Fortunately, however, we have something custom-made for the purpose: the Task Queue API. Using the Task Queue API, we can take care of the essential updates immediately - the post page itself, for example - then queue up other updates, such as the archive pages, on the task queue for later execution. Using the task queue has the extra advantage that updates can be executed in parallel.

Even better, we can make use of a new library in version 1.2.5 of the SDK, called 'deferred'. deferred is a clone of Ruby's delayed::job library, and makes it easy to enqueue function and method calls on the App ...

Blogging on App Engine, part 3: Dependencies

This is part of a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

First, a couple of things of note. Between the last post and this one, I've snuck around behind your back and made a couple of minor changes. Don't worry, none of them are major. The most noticeable of these is that I've implemented a CSS design from the excellent site styleshout; our blog will now look halfway presentable. I've also refactored the existing admin code into a number of smaller modules; if you're browsing the source, you'll notice the code is now split between '' (the webapp.RequestHandlers), '' (the datastore models), and '' (the utility functions such as those to generate content from templates).

I'm also pleased to announce that a couple of dedicated coders are following along with the series by writing their own ports of Bloggart. Sylvain is writing 'bloggartornado', a port of Bloggart to the Tornado framework, the source to which is here; a demo can be seen at Rodrigo Moraes is writing 'bloggartzeug', a port of ...

Blogging on App Engine Interlude: Editing and listing

This is part of a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

A couple of things didn't quite make it into part 2 of the series: Listing and editing posts in the admin interface. This post is a short 'interlude' between the main posts in the series, and briefly covers the changes needed for those features.

Editing posts requires surprisingly little work, thanks to our use of the Django forms library. First, we write a decorator function that we can attach to methods that require an optional post ID, loading the relevant BlogPost object for us:

def with_post(fun):
  def decorate(self, post_id=None):
    post = None
    if post_id:
      post = BlogPost.get_by_id(int(post_id))
      if not post:
    fun(self, post)
  return decorate

Then, we enhance the PostHandler to take an optional post ID argument, using the decorator we just defined. Here's the new get() method:

  def get(self, post):

If no post ID is supplied, post is None, and the form works as it used to. If a post ID is supplied, the post variable contains ...

Blogging on App Engine, part 2: Basic blogging

This is the second in a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

In this post, we'll be handling the most basic part of blogging: Submitting new posts. For this, we're going to have to create our admin interface - which will involve a fair bit of boilerplate - as well as templates for both the admin interface and the blog posts themselves. But first, we need to make a slight change to the static serving code.

In order to publish new blog posts, we need to make sure we can generate a unique URL for the post, and for that we need a new method in the static serving interface. We'll call it 'add', and define it in like so:

def add(path, body, content_type, **kwargs):
  def _tx():
    if StaticContent.get_by_key_name(path):
      return None
    return set(path, body, content_type, **kwargs)
  return db.run_in_transaction(_tx)

add() is a fairly straightforward transactional wrapper for set(), which first checks if a resource with the provided URL path already exists, and only creates it if it doesn't, returning None otherwise.

Next, we need to add routing ...

Blogging on App Engine, part 1: Static serving

This is the first in a series of articles on writing a blogging system on App Engine. An overview of what we're building is here.

As promised, today we'll be covering the static serving component of our blog-to-be. First, though, is the naming issue. There were a lot of good names proposed by readers. Unfortunately, pretty much every one of them is taken on In the end, I settled on a name suggested to me out-of-band: 'bloggart'. My wife, who loves to draw, has kindly promised to draw me a picture of a boastful looking monster to act as a mascot.

Now down to business. Create a new app called 'bloggart-demo' (or whatever you wish, really), and put the following in its app.yaml file:

application: bloggart-demo
version: live
runtime: python
api_version: 1

- url: /remote_api
  script: $PYTHON_LIB/google/appengine/ext/remote_api/
  login: admin

- url: /.*

Note that we're including remote_api right away. Without any sort of admin interface at this stage, it's going to be our only way of creating some initial content to test things out with. As discussed in the introductory post, we're separating out the ...

Win a Dell Netbook and $1000 of App Engine credit!

Just a quick note: We recently announced a competition on the App Engine blog: Develop an App Engine app that uses Twilio, and you could win a Dell Netbook and $1000 of App Engine credit! Twilio is an excellent service that lets you write sophisticated telephony applications, entirely over HTTP.

You have until October 4th to enter. I really wish I could, but as part of the team, I'm disqualified. ;)

Writing a blog system on App Engine

I'm going to spend the next few posts working through the process of writing a simple, robust and scalable blogging system for App Engine. This first post is going to be fairly dull, unfortunately, as it will serve to cover what our requirements and non-requirements are, and the general approach we're going to take to achieve those objectives. In other words: Lots of bullet points, and little to no code. Don't worry, it'll get more exciting soon.

First, let's outline what we (or at least, I) expect out of a blogging system:

  • Simple authoring. I personally don't want to juggle with WYSIWYG HTML editors in order to write blog posts - I prefer to enter markup directly. But at the same time, I don't intend to make all potential users conform to the same expectations - so we should be able to support rich text editors if they're desired.
  • Good isolation of code and markup. Users shouldn't have to understand the innards of our blogging software if all they want to do is change how the blog looks or is laid out.
  • RSS and Atom support. This should go without saying, these days ...

Handling file uploads in App Engine

This is the ninth in a series of 'Cookbook' posts describing useful strategies and functionality for writing better App Engine applications.

One issue that comes up frequently on the App Engine groups is how to handle file uploads from users. Part of the confusion arises from the fact that App Engine apps cannot write to the local filesystem. Fortunately, the Datastore comes to the rescue: We can easily write an app that accepts file uploads and stores them in the datastore, then serves them back to users.

To start, we need an HTML form users can upload files through:

  <title>File Upload</title>
  <form method="post" action="/">
    <input type="file" name="file" />
    <input type="submit" value="Upload" />

We'll also need a datastore model we can store the uploaded file in:

class DatastoreFile(db.Model):
  data = db.BlobProperty(required=True)
  mimetype = db.StringProperty(required=True)

And finally, a Request Handler that can handle the uploads:

class UploadHandler(webapp.RequestHandler):
  def get(self):
    self.response.out.write(template.render("upload.html", {}))

  def post(self):
    file = self.request.POST['file']
    entity = DatastoreFile(data=file.value, mimetype=file.type)
    file_url = "http://%s/%d/%s ...