Google Cloud Platform

webapp Blobstore Handlers

webapp includes request handler classes for working with the Blobstore API. BlobstoreUploadHandler provides logic for parsing the upload request passed via the Blobstore into BlobInfo records for further processing. BlobstoreDownloadHandler makes it easy to serve Blobstore values from any path.

These classes are provided by the google.appengine.ext.webapp.blobstore_handlers package.


Values are added to the Blobstore via file uploads posted by users or administrators of the app. The app posts a web form with a file upload field and a form action that directs the upload to the Blobstore. The app gets the form action URL by calling a function (create_upload_url()), passing it the URL of an app handler that gets called when users upload files. A webapp application can use a subclass of the BlobstoreUploadHandler class as the handler for this URL.

The get_uploads() method returns a list of BlobInfo objects, one for each uploaded file in the request. Each object contains the Blobstore key for the uploaded value, as well as metadata such as the filename and size. Each uploaded file also has a corresponding entity in the datastore with this information, so you can fetch the BlobInfo object later given a blob key, or perform a datastore query over the metadata fields. The upload handler parses this information directly from the request data, not the datastore.

By default, get_uploads() returns BlobInfo objects for all uploaded files in the request. The method also accepts a field_name argument to get just the file (or files) for a given file upload field. The return value is always a list, possibly an empty list.

import webapp2
from google.appengine.api import users
from google.appengine.ext import blobstore
from google.appengine.ext import ndb
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp.util import run_wsgi_app

# A custom datastore model for associating users with uploaded files.
class UserPhoto(ndb.Model):
  user = ndb.StringProperty()
  blob_key = ndb.BlobKeyProperty()

class PhotoUploadFormHandler(webapp2.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload_photo')
        # The method must be "POST" and enctype must be set to "multipart/form-data".
        self.response.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
        self.response.write('''Upload File: <input type="file" name="file"><br> <input type="submit"
            name="submit" value="Submit"> </form></body></html>''')

class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
            upload = self.get_uploads()[0]
            user_photo = UserPhoto(user=users.get_current_user().user_id(),

            self.redirect('/view_photo/%s' % upload.key())

app = webapp2.WSGIApplication([('/upload_form', PhotoUploadFormHandler),
                                ('/upload_photo', PhotoUploadHandler)
                              ], debug=True)

Using BlobstoreUploadHandler with Google Cloud Storage

If you use this upload handler with GCS, you'll need to get and store the full GCS object file name, since this is required to retrieve the file again from GCS. Use the function get_file_infos, which returns a list of FileInfo records corresponding to each upload. The full GCS object name, content type, creation time, and other data are available in the FileInfo. (See the link for complete details.)


To serve a Blobstore value, the application sets the X-AppEngine-BlobKey header to the value of a Blobstore key, in string form. When App Engine sees this header in the response, it serves the value of the blob as the body of the response. The webapp handler class BlobstoreDownloadHandler makes it easy to set this value in the response.

The send_blob() method takes a BlobKey object, a string key, or a BlobInfo as the blob_key_or_info argument, and sets the response data so that the blob value will be served to the user. The method takes an optional content_type argument which overrides the MIME content type of the stored blob value. By default, the blob is served with the content type set by the client that uploaded it, a content type derived from the filename, or a generic type if no other type information is available.

The send_blob() method accepts a save_as argument that determines whether the blob data is sent as raw response data or as a MIME attachment with a filename, which prompts web browsers to save the file with the given name instead of displaying it. If the value of the argument is a string, the blob is sent as an attachment, and the string value is used as the filename. If True and blob_key_or_info is a BlobInfo object, the filename from the object is used. By default, the blob data is sent as the body of the response and not as a MIME attachment.

import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp.util import run_wsgi_app

class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):

app = webapp2.WSGIApplication([('/view_photo/([^/]+)?', ViewPhotoHandler)
                              ], debug=True)

The Blobstore supports sending just part of a value instead of the full value, described as a range of byte indexes. You can provide a byte index range to BlobstoreDownloadHandler's send_blob() method in two ways. The first is to specify the range as the arguments start and end:

            # Send the first 1,000 bytes of the value.
            self.send_blob(key, start=0, end=999)

By default, the BlobstoreDownloadHandler honors the range header in the request. If you wish to block use of the original range header, provide the parameter use_range=False to send_blob():

            # Send the full value of the blob and
            # block the "range" header.
            self.send_blob(key, use_range=False)

The value of the range header is a standard HTTP byte range. BlobstoreDownloadHandler uses webob.byterange to parse this header value.