Вопрос

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')

Другие советы

The fileapi for blobstore has been deprecated, so you'll need to upload to cloud storage instead of blobstore.

import cloudstorage as gcs

filename = "<your bucket + filename>"   
with gcs.open(filename, 'w') as f:
    f.write(img)
blobstore_filename = "/gs"+filename
#this is needed if you want to continue using blob_keys.
return blobstore.BlobKey(blobstore.create_gs_key(blobstore_filename))

See the docs for gcs here

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top