API Blobstore para Python 3

Nesta página, descrevemos como usar a API Blobstore, um dos serviços em pacote legados, com o ambiente de execução do Python 3 para o ambiente padrão. O aplicativo pode acessar os serviços incluídos pelo SDK de serviços do App Engine para Python 3.

Visão geral

Como o webapp não é compatível com o Python 3, você precisa fazer algumas alterações mínimas ao migrar o código do gerenciador do Blobstore do Python 2 para o Python 3. Para usar a API Blobstore para Python 3, considere o seguinte:

  • As classes de gerenciador do Blobstore são classes utilitárias. Isso significa que as classes do gerenciador não são mais baseadas em webapp e não é possível usar o módulo blobstore_handlers fornecido pelo pacote do webapp (google.appengine.ext.webapp) ou os parâmetros webapp2.RequestHandler em subclasses desses gerenciadores.

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

As seções a seguir mostram como usar as classes BlobstoreUploadHandler e BlobstoreDownloadHandler para Python 3 em um aplicativo Flask e um aplicativo WSGI que não usa um framework Python. É possível comparar os exemplos do Python 3 com o código de exemplo do Python 2 para saber mais sobre diferenças de mudança de código.

Exemplo: aplicativo Flask

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

Compare as alterações de código feitas no Python 2 (webapp2) com o Python 3 (Flask). Veja como o aplicativo 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: aplicativo WSGI sem um framework da Web

O código para Python 3 (aplicativo WSGI) a seguir mostra como adicionar o parâmetro environ ao usar classes de gerenciador do Blobstore para um aplicativo WSGI sem um framework da Web. Observe 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 (Flask), consulte o GitHub.