API Blobstore pour Python 3

Cette page explique comment utiliser l'API Blobstore, l'un des anciens services groupés, avec l'environnement d'exécution Python 3 pour l'environnement standard. Votre application peut accéder aux services groupés via le SDK des services App Engine pour Python 3.

Aperçu

Étant donné que webapp n'est pas compatible avec Python 3, vous devez apporter des modifications minimales lors de la migration du code du gestionnaire Blobstore de Python 2 vers Python 3. Pour utiliser l'API Blobstore pour Python 3, tenez compte des points suivants :

  • Les classes du gestionnaire Blobstore sont des classes utilitaires. Cela signifie que les classes du gestionnaire ne sont plus basées sur webapp. Vous ne pouvez donc pas utiliser le module blobstore_handlers fourni par le package webapp (google.appengine.ext.webapp) ou les paramètres webapp2.RequestHandler dans les sous-classes de ces gestionnaires.

  • Toutes les méthodes des classes du gestionnaire Blobstore nécessitent le dictionnaire WSGI environ comme paramètre d'entrée.

Les sections suivantes expliquent comment utiliser les classes BlobstoreUploadHandler et BlobstoreDownloadHandler pour Python 3 dans une application Flask et une application WSGI qui n'utilise pas de framework Python. Vous pouvez comparer les exemples en Python 3 avec l'exemple de code Python 2 pour en savoir plus sur les différences de code.

Exemple : application Flask

Dans Python 3, les classes du gestionnaire Blobstore font partie du module google.appengine.ext.blobstore. Pour une application Flask, tous les appels passés aux méthodes des classes BlobstoreUploadHandler et BlobstoreDownloadHandler nécessitent le dictionnaire request.environ (request importé à partir du module flask).

Comparez les modifications de code effectuées entre Python 2 (webapp2) et Python 3 (Flask). Notez que l'application Flask utilise le paramètre request.environ dans les méthodes get_uploads() et 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()

Pour afficher l'exemple de code complet pour Python 3 (Flask), consultez GitHub.

Exemple : Application WSGI sans framework Web

Le code Python 3 (application WSGI) suivant montre comment ajouter le paramètre environ lors de l'utilisation des classes du gestionnaire Blobstore pour une application WSGI sans framework Web. Notez que le paramètre environ est utilisé dans les méthodes get_uploads() et send_blob(). Comparez-le à la version 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),
]

Pour afficher l'exemple de code complet pour Python 3, consultez GitHub.