Handling file uploads in App Engine
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:
<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:
data = db.BlobProperty(required=True)
mimetype = db.StringProperty(required=True)
And finally, a Request Handler that can handle the uploads:
file = self.request.POST['file']
entity = DatastoreFile(data=file.value, mimetype=file.type)
file_url = "http://%s/%d/%s" % (self.request.host, entity.key().id(), file.name)
self.response.out.write("Your uploaded file is now available at %s" % (file_url,))
Note that we access the uploaded file using self.request.POST rather than self.request.get(); using self.request.get("file") would only give us the actual data of the uploaded file, whilst self.request.POST["file"] returns a cgi.FieldStorage object, which gives us access to the file data, filename, and mimetype. We take care to store the mimetype in addition to the original file data so we can make sure we serve it back up with the correct mimetype.
Serving the uploaded file from the datastore is, of course, also easy:
def get(self, id, filename):
entity = DatastoreFile.get_by_id(int(id))
self.response.headers['Content-Type'] = entity.mimetype
Our handler here takes a filename in addition to the ID; the filename is purely for convenience, to make the URLs we provide more friendly. All we care about is the ID, which we use to find the file object in the datastore.
Finally, here's the webapp to glue all this together:
application = webapp.WSGIApplication([
if __name__ == "__main__":
Next, we'll be taking a break from the cookbook series, and working through the steps of building a blogging system on App Engine.
Previous Post Next Post