from __future__ import with_statement
from google.appengine.api import files
from google.appengine.ext import blobstore
def get_blob_key(self, data, _type):
# Create the file
file_name = files.blobstore.create(mime_type = _type)
# Open the file and write to it
with files.open(file_name, 'a') as f:
f.write(data)
# Finalize the file. Do this before attempting to read it.
files.finalize(file_name)
# Get the file's blob key
blob_key = files.blobstore.get_blob_key(file_name)
return blob_keyOld way:
Let's assume you would like to programmatically store an image into blobstore on Google AppEngine in Python like this:
key = blobstore_image.uploadImage(open("test.png", "rb").read())
and then serve it like this:
self.response.out.write("<img src='" + blobstore_image.getServingUrl(key) + "'>")
Well, with the normal API, that's not easily possible.
However, I created exactly this API. :)
Prerequisites:
Libraries:
You need to have a copy of Poster's encode.py in the same directory as my library.
App.yaml:
Add this to your app.yaml:
- url: /blobstore_image(/.*)? script: /tools/blobstore_image.pySpecial dev_appserver.py!
This is very important:
You need to run an additional dev_appserver.py instance if you want to use this library locally!
dev_appserver.py --port 8080 .
dev_appserver.py --port 8081 .
My library does a post request to your app, while handling the current request. Since the dev_appserver.py is single threaded this would not work. Therefor you have to run a second instance locally that handles all blobstore related operations. But don't worry you wont notice and in production the extra code is not even used :)
The library (blobstore_image.py):
#!/usr/bin/env python # DEV_APP_SERVER_BLOBSTORE_ENTITY_PORT = 8081 import os import urllib from tools.poster import multipart_encode, MultipartParam from google.appengine.api import images from google.appengine.api import urlfetch 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 def getServingUrl(key, size=None, crop=False): global DEV_APP_SERVER_BLOBSTORE_ENTITY_PORT url = images.get_serving_url(key) if development(): url = url[7:] url = ("http://localhost:%d%s" % (DEV_APP_SERVER_BLOBSTORE_ENTITY_PORT, url[url.find("/"):])) if size: url += "=s%d" if crop: url += "-c" return url def uploadImage(data): global DEV_APP_SERVER_BLOBSTORE_ENTITY_PORT params = [] params.append(MultipartParam( "file", filename='file', value=data)) payloadgen, headers = multipart_encode(params) payload = str().join(payloadgen) url = None if development(): url = urlfetch.fetch( url=("http://localhost:%d/blobstore_image/geturl" % DEV_APP_SERVER_BLOBSTORE_ENTITY_PORT)).content else: url = urlfetch.fetch( "http://%s.latest.%s.appspot.com/blobstore_image/geturl" % (os.environ["CURRENT_VERSION_ID"].split(".")[0], os.environ["APPLICATION_ID"].replace("s~", ""))).content
try: result = urlfetch.fetch( url=url, payload=payload, method=urlfetch.POST, headers=headers, deadline=10, follow_redirects=False) if "location" in result.headers: location = result.headers["location"] key = location[location.rfind("/") + 1:] return key else: return None except: return None def development(): return os.environ['SERVER_SOFTWARE'].find('Development') == 0 class GetUrl(webapp.RequestHandler): def get(self): self.response.out.write(blobstore.create_upload_url('/blobstore_image')) class UploadHandler(blobstore_handlers.BlobstoreUploadHandler): def post(self): upload_files = self.get_uploads('file') blob_info = upload_files[0] self.redirect('%s' % blob_info.key()) def main(): application = webapp.WSGIApplication( [('/blobstore_image/geturl', GetUrl), ('/blobstore_image', UploadHandler), ], debug=True) run_wsgi_app(application) if __name__ == '__main__': main()
Could this be generalized for all blobstore items?
AntwortenLöschenAbsolutely. Actually it is already working for all other items. I'm just not sure if the 2 dev_appserver.py instances share the data properly. You'll have to try out...
AntwortenLöschen