API Blobstore para Python 3

Esta página descreve como usar a API Blobstore, um dos serviços agrupados antigos, com o tempo de execução do Python 3 para o ambiente padrão. A sua app pode aceder aos serviços incluídos através do SDK dos serviços do App Engine para Python 3.

Vista geral

Uma vez que a app Web não é suportada no Python 3, tem de fazer algumas alterações mínimas quando migrar o código do controlador Blobstore do Python 2 para o Python 3. Para usar a API Blobstore para Python 3, tenha em atenção o seguinte:

  • As classes de processadores do Blobstore são classes de utilidade. Isto significa que as classes de processadores já não se baseiam na app Web e não pode usar o módulo blobstore_handlers fornecido pelo pacote da app Web (google.appengine.ext.webapp) nem os parâmetros webapp2.RequestHandler nas subclasses destes processadores.

  • Todos os métodos nas classes do controlador Blobstore requerem o dicionário WSGI como um parâmetro de entrada.environ

As secções seguintes mostram como usar as classes BlobstoreUploadHandler e BlobstoreDownloadHandler para Python 3 numa app Flask e numa app WSGI que não usa uma framework Python. Pode comparar os exemplos do Python 3 com o exemplo de código do Python 2 para saber mais sobre as diferenças de alteração de código.

Exemplo: app Flask

No Python 3, as classes de controlador Blobstore fazem parte do módulo google.appengine.ext.blobstore. Para uma app Flask, todas as chamadas feitas a métodos nas classes BlobstoreUploadHandler e BlobstoreDownloadHandler requerem o dicionário request.environ (request importado do módulo flask).

Compare as alterações de código feitas do Python 2 (webapp2) para o Python 3 (Flask). Repare como a app Flask usa o parâmetro request.environ nos métodos get_uploads() e send_blob():

Python 2 (webapp2)

class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads()[0]
        user_photo = UserPhoto(
            user=users.get_current_user().user_id(),
            blob_key=upload.key())
        user_photo.put()

        self.redirect('/view_photo/%s' % upload.key())

class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)

app = webapp2.WSGIApplication([
    ('/', PhotoUploadFormHandler),
    ('/upload_photo', PhotoUploadHandler),
    ('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)

Python 3 (Flask)

class PhotoUploadHandler(blobstore.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads(request.environ)[0]
        photo = PhotoUpload(blob_key=upload.key())
        photo.put()

        return redirect("/view_photo/%s" % upload.key())


class ViewPhotoHandler(blobstore.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            return "Photo key not found", 404
        else:
            headers = self.send_blob(request.environ, photo_key)

            # Prevent Flask from setting a default content-type.
            # GAE sets it to a guessed type if the header is not set.
            headers["Content-Type"] = None
            return "", headers


@app.route("/view_photo/<photo_key>")
def view_photo(photo_key):
    """View photo given a key."""
    return ViewPhotoHandler().get(photo_key)


@app.route("/upload_photo", methods=["POST"])
def upload_photo():
    """Upload handler called by blobstore when a blob is uploaded in the test."""
    return PhotoUploadHandler().post()

Para ver o exemplo de código completo para Python 3 (Flask), consulte o GitHub.

Exemplo: app WSGI sem uma framework Web

O seguinte código Python 3 (app WSGI) mostra como adicionar o parâmetro environ quando usar classes de controlador Blobstore para uma app WSGI sem uma framework Web. Repare como o parâmetro environ é usado nos métodos get_uploads() e send_blob() e compare-o com a versão do Python 2:

Python 2

class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads()[0]
        user_photo = UserPhoto(
            user=users.get_current_user().user_id(),
            blob_key=upload.key())
        user_photo.put()

        self.redirect('/view_photo/%s' % upload.key())

class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)

app = webapp2.WSGIApplication([
    ('/', PhotoUploadFormHandler),
    ('/upload_photo', PhotoUploadHandler),
    ('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)

Python 3

class UploadPhotoHandler(blobstore.BlobstoreUploadHandler):
    """Upload handler called by blobstore when a blob is uploaded in the test."""

    def post(self, environ):
        upload = self.get_uploads(environ)[0]
        user_photo = UserPhoto(blob_key=upload.key())
        user_photo.put()

        # Redirect to the '/view_photo/<Photo Key>' URL
        return (
            "",
            http.HTTPStatus.FOUND,
            [("Location", "/view_photo/%s" % upload.key())],
        )


class ViewPhotoHandler(blobstore.BlobstoreDownloadHandler):
    def get_photo(self, environ, photo_key):
        if not blobstore.get(photo_key):
            return "Photo key not found", http.HTTPStatus.NOT_FOUND, []
        else:
            return (
                "",
                http.HTTPStatus.OK,
                list(self.send_blob(environ, photo_key).items()),
            )

    def get(self, environ):
        photo_key = (environ["app.url_args"])[0]
        return self.get_photo(environ, photo_key)


# map urls to functions
urls = [
    (r"^$", UploadFormHandler),
    (r"upload_photo/?$", UploadPhotoHandler),
    (r"view_photo/(.+)$", ViewPhotoHandler),
]

Para ver o exemplo de código completo para Python 3, consulte o GitHub.