Webapp-Blobstore-Handler

Die "webapp"-Anwendung enthält Request-Handler-Klassen für die Arbeit mit der Blobstore API. BlobstoreUploadHandler stellt eine Logik für das Parsen der Uploadanfrage bereit, die zur weiteren Verarbeitung über Blobstore an BlobInfo-Datensätze übergeben wird. Mit BlobstoreDownloadHandler können Blobstore-Werte mühelos von einem beliebigen Pfad aus bereitgestellt werden.

BlobstoreUploadHandler

Die Werte werden über Dateiuploads dem Blobstore hinzugefügt, die von Nutzern oder Administratoren der Anwendung gesendet werden. Die Anwendung stellt ein Webformular mit einem Feld für den Dateiupload und einer Formularaktion bereit, die den Upload an den Blobstore weiterleitet. Die App erhält die URL für die Formularaktion durch Aufrufen einer Funktion (create_upload_url()) und Übergeben der URL eines Anwendungs-Handlers, der aufgerufen wird, wenn Nutzer Dateien hochladen. Eine webapp-Anwendung kann eine Unterklasse der BlobstoreUploadHandler-Klasse als Handler für diese URL verwenden.

Die Methode get_uploads() gibt eine Liste von BlobInfo-Objekten zurück, eines für jede in der Anfrage hochgeladene Datei. Die einzelnen Objekte enthalten jeweils den Blobstore-Schlüssel für den hochgeladenen Wert sowie Metadaten wie den Dateinamen und die Größe. Zu jeder hochgeladenen Datei gehört auch eine entsprechende Entität im Datenspeicher mit diesen Informationen. So können Sie das BlobInfo-Objekt später mit einem Blob-Schlüssel abrufen oder eine Datenspeicherabfrage in allen Metadatenfeldern vornehmen. Der Upload-Handler parst diese Informationen direkt aus den Anfragedaten, nicht aus dem Datenspeicher.

Standardmäßig gibt get_uploads() BlobInfo-Objekte für alle hochgeladenen Dateien in der Anfrage zurück. Die Methode akzeptiert auch ein field_name-Argument, um nur die Datei (bzw. Dateien) für ein bestimmtes Datei-Upload-Feld abzurufen. Der Rückgabewert ist immer eine Liste, die jedoch auch leer sein kann.

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

BlobstoreUploadHandler mit Google Cloud Storage verwenden

Wenn Sie diesen Upload-Handler mit Cloud Storage verwenden, müssen Sie den vollständigen Dateinamen des Cloud Storage-Objekts abrufen und speichern. Dies ist erforderlich, wenn Sie die Datei wieder aus Cloud Storage abrufen möchten. Verwenden Sie die Funktion get_file_infos, die für jeden Upload eine Liste von FileInfo-Datensätzen zurückgibt. In der FileInfo finden Sie den vollständigen Cloud Storage-Objektnamen, den Inhaltstyp, den Erstellungszeitpunkt sowie weitere Daten. Mehr erfahren Sie, wenn Sie auf den Link klicken.

BlobstoreDownloadHandler

Zur Bereitstellung eines Blobstore-Werts setzt die Anwendung den X-AppEngine-BlobKey-Header auf den Wert eines Blobstore-Schlüssels (im Stringformat). Wenn App Engine diesen Header in der Antwort findet, stellt es den Wert des Blobs als Text der Antwort bereit. Die webapp-Handler-Klasse BlobstoreDownloadHandler erleichtert die Festlegung dieses Werts in der Antwort.

Die Methode send_blob() verwendet ein BlobKey-Objekt, einen Stringschlüssel oder eine BlobInfo als blob_key_or_info-Argument und legt die Antwortdaten so fest, dass der Blob-Wert an den Nutzer geliefert. Diese Methode verwendet ein optionales content_type-Argument, das den MIME-Inhaltstyp des gespeicherten Blob-Werts überschreibt. Standardmäßig wird der Blob mit dem Inhaltstyp bereitgestellt, der von dem Client festgelegt wurde, der ihn hochgeladen hat, mit einem Inhaltstyp, der vom Dateinamen abgeleitet wurde, oder mit einem allgemeinen Typ, wenn keine anderen Typinformationen verfügbar sind.

Die send_blob()-Methode akzeptiert ein save_as-Argument, das bestimmt, ob die Blob-Daten als unverarbeitete Antwortdaten oder als MIME-Anhang mit einem Dateinamen gesendet werden. Wenn das Argument ein String ist, wird das Blob als Anhang gesendet und der Stringwert wird als Dateiname verwendet. Wenn es sich bei True und blob_key_or_info um ein BlobInfo-Objekt handelt, wird der Dateiname aus dem Objekt verwendet. Standardmäßig werden die Blob-Daten als Text der Antwort gesendet und nicht als MIME-Anhang.

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)

Der Blobstore unterstützt das Senden nur eines Teils des Werts anstatt des vollständigen Werts (angegeben als Bereich von Byte-Indizes). Ein Byte-Indexbereich kann der Methode send_blob() von BlobstoreDownloadHandler auf zwei verschiedene Weisen bereitgestellt werden. Die erste Methode besteht in der Angabe des Bereichs als Argumente start und end:

            # Send the first 1,000 bytes of the value.
            self.send_blob(key, start=0, end=999)

Standardmäßig beachtet BlobstoreDownloadHandler den range-Header in der Anfrage. Wenn Sie die Verwendung des ursprünglichen Bereichs-Headers sperren möchten, geben Sie den Parameter use_range=False für send_blob() an:

            # Send the full value of the blob and
            # block the "range" header.
            self.send_blob(key, use_range=False)

Der Wert des range-Headers ist ein Standard-HTTP-Bytebereich. BlobstoreDownloadHandler verwendet webob.byterange, um diesen Headerwert zu parsen.

Komplette Beispielanwendung

In der folgenden Beispielanwendung wird über die Haupt-URL der Anwendung das Formular geladen, das den Nutzer zum Hochladen einer Datei auffordert. Der Upload-Handler ruft sofort den Download-Handler auf, um die Daten bereitzustellen. Das vereinfacht die Beispielanwendung. In der Praxis würden Sie wahrscheinlich nicht die Haupt-URL verwenden, um das Hochladen von Daten anzufordern. Und Sie würden ein gerade hochgeladenes Blob auch nicht sofort bereitstellen.

from google.appengine.api import users
from google.appengine.ext import blobstore
from google.appengine.ext import ndb
from google.appengine.ext.webapp import blobstore_handlers
import webapp2

# This datastore model keeps track of which users uploaded which photos.
class UserPhoto(ndb.Model):
    user = ndb.StringProperty()
    blob_key = ndb.BlobKeyProperty()

class PhotoUploadFormHandler(webapp2.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload_photo')
        # To upload files to the blobstore, the request method must be "POST"
        # and enctype must be set to "multipart/form-data".
        self.response.out.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
  Upload File: <input type="file" name="file"><br>
  <input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))

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)