Brett
Brett

Reputation: 12007

GAE - Uploading an image from a mobile device to blobstore

I have successfully been able to upload images to my Google App Engine Blobstore using the provided code here (in one of the comments, which is majorly based on the GAE docs).

Here is the full code for reference:

import os
import urllib

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

class MainHandler(webapp.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload')
        self.response.out.write('<html><body>')
        self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
        self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit" name="submit" value="Submit"> </form></body></html>""")

        for b in blobstore.BlobInfo.all():
            self.response.out.write('<li><a href="/serve/%s' % str(b.key()) + '">' + str(b.filename) + '</a>')

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload_files = self.get_uploads('file')
        blob_info = upload_files[0]
        self.redirect('/')

class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, blob_key):
        blob_key = str(urllib.unquote(blob_key))
        if not blobstore.get(blob_key):
            self.error(404)
        else:
            self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)

def main():
    application = webapp.WSGIApplication(
          [('/', MainHandler),
           ('/upload', UploadHandler),
           ('/serve/([^/]+)?', ServeHandler),
          ], debug=True)
    run_wsgi_app(application)

if __name__ == '__main__':
  main()

However, this code requires that the upload url be created on a GET request prior to POST request containing the image data:

def get(self):
  upload_url = blobstore.create_upload_url('/upload')

When I try to send the image from a mobile device, I'd like to push the server code into a single code-block under the def post(self): function, and I'm having trouble doing this.

Moving the above line into the def post(self): code doesn't seem to do the trick.

Any ideas?

Cheers! Brett

Upvotes: 3

Views: 800

Answers (2)

Nathan Do
Nathan Do

Reputation: 2035

yes you can make it one single block of code using urlfetch. Here is my approach:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload_files = self.get_uploads('file')
        if len(upload_files) > 0 :
            blob_info = upload_files[0]
            self.response.write(str(blob_info.key()))
        else:
            self.error(404) 

class SomeHandler(webapp.RequestHandler):
    def post(self):
        file = self.request.POST.get('file')
        if (file is not None):
            # Use urlfetch to call to the blob upload url and get result
            # Just copy the same request body and header and pass to UploadHandler here
            result = urlfetch.fetch(
                url= blobstore.create_upload_url('/upload'),
                payload=self.request.body,
                method=urlfetch.POST,
                headers=self.request.headers)
            if result.status_code == 200:
                blob_key_str = result.content
                # Get blob key
                blob_key = blobstore.BlobKey(blob_key_str)
                # Maybe a url for the file
                blob_url = images.get_serving_url(blob_key_str, 400)

This way you can always Upload file to SomeHandler rather than have to obtain the upload URL first then only Upload.

Hope it helps!

Upvotes: 2

Peter Knego
Peter Knego

Reputation: 80340

This will not work with the default Blobstore upload handler: it needs two requests: first to create a one-time download url and the second to actually do POST to this url.

If you want to do all in one go, create your own file upload handler and use new Blobstore API to write files.

Upvotes: 0

Related Questions