Austin Chau
April 2008
Note: This article is also available for Java .
A picture is worth a thousand words. This is definitely true with today's web applications where images play a big part in reaching the audience. Google App Engine allows you to store and serve images quickly and easily through its datastore. The Python interface includes a data modeling API and GQL, our very own query language. In this short article, I will walk you through how to use the Datastore API to store and serve images, using code snippets for storing and retrieving movie information.
Storing Images in the Datastore
For starters, we would like to store each movie in the application as an object of the datastore. This is accomplished by defining a class that models a movie. The Movie class below defines all the attributes a Movie object would have. One of the defined attributes is "picture", which represents the binary data of a jpeg image for that movie. To handle the images properly, we must store them as Blobs, therefore we need to declare the picture as a BlobProperty .
Note: Do not confuse this with the Blobstore API which can also be used to store large data objects such as images but does not do so via the datastore. This article uses the datastore exclusively.
class Movie(db.Model) title = db.StringProperty() picture = db.BlobProperty(default=None) ...
Now that we have the model defined, we can start using it to store movie objects. We can get movie data from a remote source and feed it into the application. To do this, use the Google App Engine's URL Fetch API which retrieves data from both HTTP and HTTPS URLs. The urlfetch.Fetch() method can be used to fetch the binary content of a remote image. We simply need to supply the URL of the image as the argument.
Next, create a Blob object by passing the content attribute of the fetched result (a string representation of the binary image) as the argument and assign it to the picture attribute of a Movie object. The
put()
method is then called to commit the change to the datastore.
movie = Movie() ... movie.picture = db.Blob(urlfetch.Fetch(picture_url).content) movie.put()
Retrieving & Displaying Images
Now that the objects are populated in our Movie datastore, let's set up a request handler to retrieve them dynamically from the datastore and render the objects back to the browser as images.
First, we create a GetImage class to define the GET request handler. The first thing the request handler does is retrieve the value of 'title' from the URL parameter. Then it retrieves the Movie object that matches the title from the datastore by calling the
getMovie()
method.
Once we have the reference to the Movie object, we can access its "picture" attribute. In order for the browser to properly render the image, we set the
HTTP Content-Type
header as
'image/jpeg'
.
class GetImage(webapp.RequestHandler): def get(self): title = self.request.get('title') movie = getMovie(title) if (movie and movie.picture): self.response.headers['Content-Type'] = 'image/jpeg' self.response.out.write(movie.picture) else: self.redirect('/static/noimage.jpg')
The
getMovie()
method contains a simple GQL query that retrieves a movie object that matches the title.
def getMovie(title): result = db.GqlQuery("SELECT * FROM Movie WHERE title = :1 LIMIT 1", title).fetch(1) if (len(result) > 0): return result[0] else: return None
To make it easy to access the images of the movies in the application, we can map the
GetImage
class to the URL path
'/image'
. Here, we have chosen to use the webapp module to handle the
GET
request:
apps_binding = [] ... apps_binding.append(('/image', GetImage)) application = webapp.WSGIApplication(apps_binding, debug=True) wsgiref.handlers.CGIHandler().run(application)
Now when a visitor visits the URL - http://mydomain.com/image?title=matrix, an image for the movie "matrix" is returned to the browser.
Resources
We have just shown you how you can easily serve images from your Google App Engine's datastore. Now it's time for you to get your hands dirty with code! Check out the resources below to get started on building your next great app: