I have an image file extracted from a url by using urlfetch api of python google app engine.
img = urlfetch.fetch(url).content
I want to upload it to the blobstore in order to be able to serve it to the users. Hence, I'll be willing to save the blob_key to the datastore. As given in the documentations of Google App Engine Blobstore, I do not want to make a upload page for the user as this work is to be done on the server side.
What should be the steps to achieve this?
UPDATE With the arrival of app engine 1.9.0 an application can use the default GCS bucket, which provides an already configured bucket with FREE QUOTA!
More details here
You can also send a multi-part form to a blobstore upload_url.
This is my code to upload a blob to the blobstore:
from __future__ import unicode_literals
import webapp2
import mimetypes
import logging
from google.appengine.ext.ndb import blobstore
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.api import urlfetch
from google.appengine.runtime import DeadlineExceededError
CRLF = b'\r\n'
BOUNDERY = b'--Th15-Is-ThE-BoUnDeRy--'
def _encode_multipart(_fields=None, _files=None):
""" Generator inserts fields and files to create a multipart payload """
for (field_name, field_value) in _fields or []:
yield b'--' + BOUNDERY + CRLF
yield b'Content-Disposition: form-data; name="%s"' % str(field_name) + CRLF
yield CRLF
yield str(field_value) + CRLF
for (file_name, file_data) in _files or []:
yield b'--' + BOUNDERY + CRLF
yield b'Content-Disposition: form-data; name="file"; filename="%s"' \
% str(file_name) + CRLF
yield b'Content-Type: %s' % mimetypes.guess_type(file_name)[0] + CRLF
yield CRLF
yield file_data + CRLF
yield b'--%s--' % BOUNDERY + CRLF
def create_upload_url(for_url):
return blobstore.create_upload_url(for_url, max_bytes_per_blob=1048576)
def _fetch_blob_update(payload):
upload_url = create_upload_url(webapp2.uri_for('blob_update', _full=True))
try:
response = urlfetch.fetch(
url=upload_url,
payload=payload,
method=urlfetch.POST,
deadline=40,
follow_redirects=False,
headers={b'Content-Type': str('multipart/form-data; boundary=%s' % BOUNDERY)}
)
if response.status_code != 200:
logging.error('URL : %s fetch ERROR : %d' % (upload_url, response.status_code))
return None
else:
return response.content
except (urlfetch.DownloadError, DeadlineExceededError), e:
logging.error('fetch %s download or deadline error, exception : %s'
% (upload_url, str(e)))
return None
def blob_update_by_upload(ndb_key, blob):
""" update blob using upload to the blobstore """
result = _fetch_blob_update(b''.join(_encode_multipart(_files=[(ndb_key.id(), blob)])))
return blobstore.BlobKey(result)
class BlobUpdate(blobstore_handlers.BlobstoreUploadHandler):
""" has named route : blob_update """
def post(self):
""" blob upload handler returns the new blobkey """
blob_info = self.get_uploads('file')[0]
self.response.headers[b'Content-Type'] = b'text/plain'
self.response.write(str(blob_info.key()))
Route:
webapp2.Route(r'/blob_update', handler='....BlobUpdate', name='blob_update')