App Engine Blobstore zu Cloud Storage migrieren

In dieser Anleitung wird beschrieben, wie Sie von App Engine Blobstore zu Cloud Storage migrieren.

Cloud Storage ähnelt App Engine Blobstore, da Sie mit Cloud Storage große Datenobjekte (Blobs) bereitstellen können, z. B. Video- oder Bilddateien, und Ihren Nutzern das Hochladen großer Datendateien ermöglichen können. Während auf App Engine Blobstore nur über die gebündelten App Engine-Legacy-Dienste zugegriffen werden kann, ist Cloud Storage ein eigenständiges Google Cloud-Produkt, auf das über die Cloud-Clientbibliotheken zugegriffen wird. Cloud Storage bietet Ihrer Anwendung eine modernere Objektspeicherlösung und bietet Ihnen die Flexibilität, später zu Cloud Run oder einer anderen Hosting-Plattform der Google Cloud-Anwendung zu migrieren.

Bei Google Cloud-Projekten, die nach November 2016 erstellt wurden, verwendet Blobstore im Hintergrund Cloud Storage-Buckets. Wenn Sie Ihre Anwendung also zu Cloud Storage migrieren, bleiben alle vorhandenen Objekte und Berechtigungen in diesen vorhandenen Cloud Storage-Buckets unverändert. Sie können auch über die Cloud-Clientbibliotheken für Cloud Storage auf diese vorhandenen Buckets zugreifen.

Wichtige Unterschiede und Gemeinsamkeiten

In Cloud Storage sind die folgenden Blobstore-Abhängigkeiten und -Einschränkungen ausgeschlossen:

  • Die Blobstore API für Python 2 ist von webapp abhängig.
  • Die Blobstore API für Python 3 verwendet Dienstprogrammklassen für die Verwendung von Blobstore-Handlern.
  • In Blobstore können maximal 500 Dateien hochgeladen werden. Die Anzahl der Objekte, die Sie in einem Cloud Storage-Bucket erstellen können, ist nicht begrenzt.

Cloud Storage unterstützt Folgendes nicht:

  • Blobstore-Handler-Klassen
  • Blobstore-Objekte

Gemeinsamkeiten von Cloud Storage und App Engine Blobstore:

  • Kann große Datenobjekte in einer Laufzeitumgebung lesen und schreiben sowie statische große Datenobjekte wie Filme, Bilder oder andere statische Inhalte speichern und bereitstellen. Das Objektgrößenlimit für Cloud Storage beträgt 5 TiB.
  • Ermöglicht das Speichern von Objekten in einem Cloud Storage-Bucket.
  • Bietet eine kostenlose Stufe.

Hinweis

  • Sie sollten sich über die Preise und Kontingente für Cloud Storage informieren:
  • Sie sollten eine vorhandene App Engine-Anwendung für Python 2 oder Python 3 haben, die Blobstore verwendet.
  • Die Beispiele in dieser Anleitung zeigen eine Anwendung, die mithilfe des Flask-Frameworks zu Cloud Storage migriert wird. Beachten Sie, dass Sie bei der Migration zu Cloud Storage ein beliebiges Web-Framework verwenden können, einschließlich webapp2.

Überblick

Im Großen und Ganzen setzt sich die Migration von App Engine Blobstore zu Cloud Storage aus den folgenden Schritten zusammen:

  1. Konfigurationsdateien aktualisieren
  2. Python-Anwendung aktualisieren:
    • Web-Framework aktualisieren
    • Cloud Storage importieren und initialisieren
    • Blobstore-Handler aktualisieren
    • Optional: Datenmodell aktualisieren, wenn Cloud NDB oder App Engine NDB verwendet wird
  3. Anwendung testen und bereitstellen

Konfigurationsdateien aktualisieren

Aktualisieren Sie vor dem Ändern des Anwendungscodes für die Migration von Blobstore zu Cloud Storage Ihre Konfigurationsdateien, um die Cloud Storage-Bibliothek zu verwenden.

  1. Aktualisieren Sie die Datei app.yaml. Folgen Sie der Anleitung für Ihre Python-Version:

    Python 2

    Für Python 2-Anwendungen:

    1. Entfernen Sie den Abschnitt handlers und alle unnötigen webapp-Abhängigkeiten im Abschnitt libraries.
    2. Wenn Sie Cloud-Clientbibliotheken verwenden, fügen Sie die neuesten Versionen der grpcio- und setuptools-Bibliotheken hinzu.
    3. Fügen Sie die Bibliothek ssl hinzu, da dies für Cloud Storage erforderlich ist.

    Hier sehen Sie eine app.yaml-Beispieldatei mit den Änderungen:

    runtime: python27
    threadsafe: yes
    api_version: 1
    
    handlers:
    - url: /.*
      script: main.app
    
    libraries:
    - name: grpcio
      version: latest
    - name: setuptools
      version: latest
    - name: ssl
      version: latest
    

    Python 3

    Löschen Sie bei Python 3-Anwendungen alle Zeilen mit Ausnahme des Elements runtime. Beispiel:

    runtime: python310 # or another support version
    

    Die Python 3-Laufzeit installiert Bibliotheken automatisch. Sie müssen also keine integrierten Bibliotheken aus der vorherigen Python 2-Laufzeit angeben. Wenn Ihre Python 3-Anwendung bei der Migration zu Cloud Storage andere gebündelte Legacy-Dienste verwendet, lassen Sie die Datei app.yaml unverändert.

  2. Aktualisieren Sie die Datei requirements.txt. Folgen Sie der Anleitung für Ihre Python-Version:

    Python 2

    Fügen Sie die Cloud-Clientbibliotheken für Cloud Storage der Liste der Abhängigkeiten in der Datei requirements.txt hinzu.

    google-cloud-storage
    

    Führen Sie dann pip install -t lib -r requirements.txt aus, um die Liste der verfügbaren Bibliotheken für Ihre Anwendung zu aktualisieren.

    Python 3

    Fügen Sie die Cloud-Clientbibliotheken für Cloud Storage der Liste der Abhängigkeiten in der Datei requirements.txt hinzu.

    google-cloud-storage
    

    App Engine installiert diese Abhängigkeiten während der Anwendungsbereitstellung in der Python 3-Laufzeit automatisch. Löschen Sie daher den Ordner lib, falls vorhanden.

  3. Wenn Ihre Python 2-Anwendung integrierte oder kopierte Bibliotheken verwendet, müssen Sie diese Pfade in der Datei appengine_config.py angeben:

    import pkg_resources
    from google.appengine.ext import vendor
    
    # Set PATH to your libraries folder.
    PATH = 'lib'
    # Add libraries installed in the PATH folder.
    vendor.add(PATH)
    # Add libraries to pkg_resources working set to find the distribution.
    pkg_resources.working_set.add_entry(PATH)
    

Python-Anwendung aktualisieren

Nachdem Sie die Konfigurationsdateien geändert haben, aktualisieren Sie Ihre Python-Anwendung.

Python 2-Web-Framework aktualisieren

Für Python 2-Anwendungen, die das Framework webapp2 verwenden, wird empfohlen, das veraltete webapp2-Framework zu migrieren. Informationen zum Enddatum der Python 2-Unterstützung finden Sie im Zeitplan für die Laufzeitunterstützung.

Sie können zu einem anderen Web-Framework wie Flask, Django oder WSGI migrieren. Da Cloud Storage Abhängigkeiten von webapp2 ausschließt und Blobstore-Handler nicht unterstützt werden, können Sie andere webapp-bezogene Bibliotheken löschen oder ersetzen.

Wenn Sie weiterhin webapp2 verwenden, beachten Sie, dass in den Beispielen in dieser Anleitung Cloud Storage mit Flask verwendet wird.

Wenn Sie zusätzlich zu Cloud Storage die Google Cloud-Dienste verwenden oder Zugriff auf die neuesten Laufzeitversionen erhalten möchten, sollten Sie Ihre Anwendung auf die Python 3-Laufzeit aktualisieren. Weitere Informationen finden Sie unter Übersicht über die Migration von Python 2 zu Python 3.

Cloud Storage importieren und initialisieren

Ändern Sie die Anwendungsdateien, indem Sie die Import- und Initialisierungszeilen aktualisieren:

  1. Entfernen Sie Blobstore-Importanweisungen wie die folgenden:

    import webapp2
    from google.appengine.ext import blobstore
    from google.appengine.ext.webapp import blobstore_handlers
    
  2. Fügen Sie die Importanweisungen für Cloud Storage und die Google-Authentifizierungsbibliotheken so hinzu:

    import io
    from flask import (Flask, abort, redirect, render_template,
    request, send_file, url_for)
    from google.cloud import storage
    import google.auth
    

    Die Google-Authentifizierungsbibliothek ist erforderlich, um dieselbe Projekt-ID abzurufen, die in Blobstore für Cloud Storage verwendet wurde. Importieren Sie gegebenenfalls andere Bibliotheken wie Cloud NBD in Ihre Anwendung.

  3. Erstellen Sie einen neuen Client für Cloud Storage und geben Sie den in Blobstore verwendeten Bucket an. Beispiel:

    gcs_client = storage.Client()
    _, PROJECT_ID = google.auth.default()
    BUCKET = '%s.appspot.com' % PROJECT_ID
    

    Bei Google Cloud-Projekten nach November 2016 schreibt Blobstore in einen Cloud Storage-Bucket, der nach der URL Ihrer Anwendung benannt ist und das Format PROJECT_ID.appspot.com hat. Sie verwenden die Google-Authentifizierung, um die Projekt-ID abzurufen und den Cloud Storage-Bucket anzugeben, der zum Speichern von Blobs in Blobstore verwendet wird.

Blobstore-Handler aktualisieren

Da Cloud Storage die Blobstore-Handler für Upload und Download nicht unterstützt, müssen Sie eine Kombination aus Cloud Storage-Funktionalität, dem io-Standardbibliotheksmodul, Ihrem Web-Framework und Python-Dienstprogrammen verwenden, um Objekte (Blobs) in Cloud Storage hoch- und herunterzuladen.

Im Folgenden wird gezeigt, wie die Blobstore-Handler mit Flask als Beispiel-Web-Framework aktualisiert werden:

  1. Ersetzen Sie die Blobstore-Upload-Handler-Klassen durch eine Uploadfunktion in Flask. Folgen Sie der Anleitung für Ihre Python-Version:

    Python 2

    Blobstore-Handler in Python 2 sind webapp2-Klassen, wie im folgenden Blobstore-Beispiel gezeigt:

    class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
        'Upload blob (POST) handler'
        def post(self):
            uploads = self.get_uploads()
            blob_id = uploads[0].key() if uploads else None
            store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
            self.redirect('/', code=307)
    ...
    app = webapp2.WSGIApplication([
        ('/', MainHandler),
        ('/upload', UploadHandler),
        ('/view/([^/]+)?', ViewBlobHandler),
    ], debug=True)
    

    So verwenden Sie Cloud Storage:

    1. Ersetzen Sie die Webapp-Uploadklasse durch eine Flask-Uploadfunktion.
    2. Ersetzen Sie den Upload-Handler und das Routing durch eine Flask-POST-Methode, die mit Routing dekoriert ist.

    Aktualisiertes Codebeispiel:

    @app.route('/upload', methods=['POST'])
    def upload():
        'Upload blob (POST) handler'
        fname = None
        upload = request.files.get('file', None)
        if upload:
            fname = secure_filename(upload.filename)
            blob = gcs_client.bucket(BUCKET).blob(fname)
            blob.upload_from_file(upload, content_type=upload.content_type)
        store_visit(request.remote_addr, request.user_agent, fname)
        return redirect(url_for('root'), code=307)
    

    Im aktualisierten Cloud Storage-Codebeispiel identifiziert die Anwendung jetzt Objektartefakte anhand ihres Objektnamens (fname) anstelle von blob_id. Das Routing wird ebenfalls am Ende der Anwendungsdatei ausgeführt.

    Zum Abrufen des hochgeladenen Objekts wird die Methode get_uploads() von Blobstore durch die Methode request.files.get() von Flask ersetzt. In Flask können Sie die secure_filename()-Methode zum Abrufen eines Namens ohne Pfadzeichen, wie /, für die Datei verwenden und das Objekt mithilfe von gcs_client.bucket(BUCKET).blob(fname) identifizieren, um den Bucket- und den Objektnamen anzugeben.

    Der Cloud Storage-Aufruf upload_from_file() führt den Upload wie im aktualisierten Beispiel gezeigt durch.

    Python 3

    Die Upload-Handler-Klasse in Blobstore für Python 3 ist eine Dienstprogrammklasse und erfordert die Verwendung des WSGI-Wörterbuchs environ als Eingabeparameter, wie im folgenden Blobstore-Beispiel dargestellt:

    class UploadHandler(blobstore.BlobstoreUploadHandler):
        'Upload blob (POST) handler'
        def post(self):
            uploads = self.get_uploads(request.environ)
            if uploads:
                blob_id = uploads[0].key()
                store_visit(request.remote_addr, request.user_agent, blob_id)
            return redirect('/', code=307)
    ...
    @app.route('/upload', methods=['POST'])
    def upload():
        """Upload handler called by blobstore when a blob is uploaded in the test."""
        return UploadHandler().post()
    

    Wenn Sie Cloud Storage verwenden möchten, ersetzen Sie die Blobstore-Methode get_uploads(request.environ) durch die Flask-Methode request.files.get().

    Aktualisiertes Codebeispiel:

    @app.route('/upload', methods=['POST'])
    def upload():
        'Upload blob (POST) handler'
        fname = None
        upload = request.files.get('file', None)
        if upload:
            fname = secure_filename(upload.filename)
            blob = gcs_client.bucket(BUCKET).blob(fname)
            blob.upload_from_file(upload, content_type=upload.content_type)
        store_visit(request.remote_addr, request.user_agent, fname)
        return redirect(url_for('root'), code=307)
    

    Im aktualisierten Cloud Storage-Codebeispiel identifiziert die Anwendung jetzt Objektartefakte anhand ihres Objektnamens (fname) anstelle von blob_id. Das Routing wird ebenfalls am Ende der Anwendungsdatei ausgeführt.

    Zum Abrufen des hochgeladenen Objekts wird die Methode get_uploads() von Blobstore durch die Methode request.files.get() von Flask ersetzt. In Flask können Sie die secure_filename()-Methode zum Abrufen eines Namens ohne Pfadzeichen, wie /, für die Datei verwenden und das Objekt mithilfe von gcs_client.bucket(BUCKET).blob(fname) identifizieren, um den Bucket- und den Objektnamen anzugeben.

    Die Methode upload_from_file() von Cloud Storage führt den Upload wie im aktualisierten Beispiel gezeigt durch.

  2. Ersetzen Sie die Blobstore-Download-Handler-Klassen durch eine Downloadfunktion in Flask. Folgen Sie der Anleitung für Ihre Python-Version:

    Python 2

    Das folgende Download-Handler-Beispiel zeigt die Verwendung der Klasse BlobstoreDownloadHandler, die webapp2 verwendet:

    class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
        'view uploaded blob (GET) handler'
        def get(self, blob_key):
            self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)
    ...
    app = webapp2.WSGIApplication([
        ('/', MainHandler),
        ('/upload', UploadHandler),
        ('/view/([^/]+)?', ViewBlobHandler),
    ], debug=True)
    

    So verwenden Sie Cloud Storage:

    1. Aktualisieren Sie die Methode send_blob() von Blobstore, um die Methode download_as_bytes() von Cloud Storage zu verwenden.
    2. Ändern Sie das Routing von webapp2 in Flask.

    Aktualisiertes Codebeispiel:

    @app.route('/view/<path:fname>')
    def view(fname):
        'view uploaded blob (GET) handler'
        blob = gcs_client.bucket(BUCKET).blob(fname)
        try:
            media = blob.download_as_bytes()
        except exceptions.NotFound:
            abort(404)
        return send_file(io.BytesIO(media), mimetype=blob.content_type)
    

    Im aktualisierten Cloud Storage-Codebeispiel dekoriert Flask die Route in der Flask-Funktion und identifiziert das Objekt mit '/view/<path:fname>'. Cloud Storage identifiziert das blob-Objekt anhand des Objektnamens und des Bucket-Namens und verwendet die Methode download_as_bytes(), um das Objekt als Bytes herunterzuladen, statt die Methode send_blob aus Blobstore zu verwenden. Wenn das Artefakt nicht gefunden wird, gibt die Anwendung den HTTP-Fehler 404 zurück.

    Python 3

    Wie beim Upload-Handler ist die Download-Handler-Klasse in Blobstore für Python 3 eine Dienstprogrammklasse. Dafür muss das WSGI-Wörterbuch environ als Eingabeparameter verwendet werden, wie im folgenden Blobstore-Beispiel gezeigt:

    class ViewBlobHandler(blobstore.BlobstoreDownloadHandler):
        'view uploaded blob (GET) handler'
        def get(self, blob_key):
            if not blobstore.get(blob_key):
                return "Photo key not found", 404
            else:
                headers = self.send_blob(request.environ, blob_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/<blob_key>')
    def view_photo(blob_key):
        """View photo given a key."""
        return ViewBlobHandler().get(blob_key)
    

    Wenn Sie Cloud Storage verwenden möchten, ersetzen Sie send_blob(request.environ, blob_key) von Blobstore durch die Cloud Storage-Methode blob.download_as_bytes().

    Aktualisiertes Codebeispiel:

    @app.route('/view/<path:fname>')
    def view(fname):
        'view uploaded blob (GET) handler'
        blob = gcs_client.bucket(BUCKET).blob(fname)
        try:
            media = blob.download_as_bytes()
        except exceptions.NotFound:
            abort(404)
        return send_file(io.BytesIO(media), mimetype=blob.content_type)
    

    Im aktualisierten Cloud Storage-Codebeispiel wird blob_key durch fname ersetzt und Flask identifiziert das Objekt mithilfe der URL '/view/<path:fname>'. Die Methode gcs_client.bucket(BUCKET).blob(fname) wird zum Ermitteln des Dateinamens und des Bucket-Namens verwendet. Die download_as_bytes()-Methode von Cloud Storage lädt das Objekt als Bytes herunter, statt die Methode send_blob() von Blobstore zu verwenden.

  3. Wenn Ihre Anwendung einen Haupt-Handler verwendet, ersetzen Sie die Klasse MainHandler durch die Funktion root() in Flask. Folgen Sie der Anleitung für Ihre Python-Version:

    Python 2

    Im Folgenden finden Sie ein Beispiel für die Verwendung der MainHandler-Klasse von Blobstore:

    class MainHandler(BaseHandler):
        'main application (GET/POST) handler'
        def get(self):
            self.render_response('index.html',
                    upload_url=blobstore.create_upload_url('/upload'))
    
        def post(self):
            visits = fetch_visits(10)
            self.render_response('index.html', visits=visits)
    
    app = webapp2.WSGIApplication([
        ('/', MainHandler),
        ('/upload', UploadHandler),
        ('/view/([^/]+)?', ViewBlobHandler),
    ], debug=True)
    

    So verwenden Sie Cloud Storage:

    1. Entfernen Sie die Klasse MainHandler(BaseHandler), da Flask das Routing für Sie übernimmt.
    2. Vereinfachen Sie den Blobstore-Code mit Flask.
    3. Entfernen Sie das webapp-Routing am Ende.

    Aktualisiertes Codebeispiel:

    @app.route('/', methods=['GET', 'POST'])
    def root():
        'main application (GET/POST) handler'
        context = {}
        if request.method == 'GET':
            context['upload_url'] = url_for('upload')
        else:
            context['visits'] = fetch_visits(10)
        return render_template('index.html', **context)
    

    Python 3

    Wenn Sie Flask verwendet haben, haben Sie keine MainHandler-Klasse. Ihre Flask-Root-Funktion muss jedoch aktualisiert werden, wenn Blobstore verwendet wird. Im folgenden Beispiel wird die blobstore.create_upload_url('/upload')-Funktion verwendet:

    @app.route('/', methods=['GET', 'POST'])
    def root():
        'main application (GET/POST) handler'
        context = {}
        if request.method == 'GET':
            context['upload_url'] = blobstore.create_upload_url('/upload')
        else:
            context['visits'] = fetch_visits(10)
        return render_template('index.html', **context)
    

    Um Cloud Storage zu verwenden, ersetzen Sie die Funktion blobstore.create_upload_url('/upload') durch die Methode url_for() von Flask, um die URL für die Funktion upload() abzurufen.

    Aktualisiertes Codebeispiel:

    @app.route('/', methods=['GET', 'POST'])
    def root():
        'main application (GET/POST) handler'
        context = {}
        if request.method == 'GET':
            context['upload_url'] = url_for('upload') # Updated to use url_for
        else:
            context['visits'] = fetch_visits(10)
        return render_template('index.html', **context)
    

Anwendung testen und bereitstellen

Mit dem lokalen Entwicklungsserver können Sie testen, ob Ihre Anwendung ausgeführt wird. Sie können Cloud Storage aber erst testen, wenn Sie eine neue Version bereitgestellt haben, da alle Cloud Storage-Anfragen über das Internet an einen tatsächlichen Cloud Storage-Bucket gesendet werden müssen. Informationen zum lokalen Ausführen der Anwendung finden Sie unter Anwendung testen und bereitstellen. Stellen Sie dann eine neue Version bereit, um zu prüfen, ob die Anwendung wie zuvor funktioniert.

Anwendungen, die App Engine NDB oder Cloud NDB verwenden

Sie müssen Ihr Datastore-Datenmodell aktualisieren, wenn Ihre Anwendung App Engine NDB oder Cloud NDB verwendet, um Blobstore-bezogene Attribute einzuschließen.

Datenmodell aktualisieren

Da die BlobKey-Attribute aus NDB von Cloud Storage nicht unterstützt werden, müssen Sie die Blobstore-bezogenen Zeilen ändern, um integrierte Entsprechungen aus NDB, Web-Frameworks oder von einem anderen Ort zu verwenden.

So aktualisieren Sie Ihr Datenmodell:

  1. Suchen Sie die Zeilen wie die folgenden, die BlobKey im Datenmodell verwenden:

    class Visit(ndb.Model):
        'Visit entity registers visitor IP address & timestamp'
        visitor   = ndb.StringProperty()
        timestamp = ndb.DateTimeProperty(auto_now_add=True)
        file_blob = ndb.BlobKeyProperty()
    
  2. Ersetzen Sie ndb.BlobKeyProperty() durch ndb.StringProperty():

    class Visit(ndb.Model):
        'Visit entity registers visitor IP address & timestamp'
        visitor   = ndb.StringProperty()
        timestamp = ndb.DateTimeProperty(auto_now_add=True)
        file_blob = ndb.StringProperty() # Modified from ndb.BlobKeyProperty()
    
  3. Wenn Sie während der Migration auch ein Upgrade von App Engine NDB auf Cloud NDB durchführen, finden Sie in der Cloud NDB-Migrationsanleitung Hinweise zum Refaktorieren des NDB-Codes für die Verwendung von Python-Kontextmanagern.

Abwärtskompatibilität für das Datastore-Datenmodell

Wenn im vorherigen Abschnitt ndb.BlobKeyProperty durch ndb.StringProperty ersetzt wurde, ist die Anwendung nicht mehr abwärtskompatibel. Das bedeutet, dass die Anwendung ältere Einträge, die von Blobstore erstellt wurden, nicht verarbeiten kann. Wenn Sie alte Daten beibehalten möchten, erstellen Sie ein neues Feld für neue Cloud Storage-Einträge, statt das Feld ndb.BlobKeyProperty zu aktualisieren, und erstellen Sie eine Funktion, um die Daten zu normalisieren.

Nehmen Sie in den Beispielen in den vorherigen Abschnitten die folgenden Änderungen vor:

  1. Erstellen Sie bei der Definition Ihres Datenmodells zwei separate Attributfelder. Verwenden Sie das Attribut file_blob, um von Blobstore erstellte Objekte zu identifizieren, und das Attribut file_gcs, um von Cloud Storage erstellte Objekte zu identifizieren:

    class Visit(ndb.Model):
        'Visit entity registers visitor IP address & timestamp'
        visitor   = ndb.StringProperty()
        timestamp = ndb.DateTimeProperty(auto_now_add=True)
        file_blob = ndb.BlobKeyProperty()  # backwards-compatibility
        file_gcs  = ndb.StringProperty()
    
  2. Suchen Sie die Zeilen wie die folgenden, die auf neue Besuche verweisen:

    def store_visit(remote_addr, user_agent, upload_key):
        'create new Visit entity in Datastore'
        with ds_client.context():
            Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                    file_blob=upload_key).put()
    
  3. Ändern Sie den Code so, dass file_gcs für die neuesten Einträge verwendet wird. Beispiel:

    def store_visit(remote_addr, user_agent, upload_key):
        'create new Visit entity in Datastore'
        with ds_client.context():
            Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                    file_gcs=upload_key).put() # change file_blob to file_gcs for new requests
    
  4. Erstellen Sie eine neue Funktion, um die Daten zu normalisieren. Das folgende Beispiel zeigt die Verwendung von ETL (Extrahieren, Transformieren, Laden), um alle Besuche zu durchlaufen. Mithilfe der Besucher- und Zeitstempeldaten wird geprüft, ob file_gcs oder file_gcs existiert:

    def etl_visits(visits):
        return [{
                'visitor': v.visitor,
                'timestamp': v.timestamp,
                'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
                        and v.file_gcs else v.file_blob
                } for v in visits]
    
  5. Suchen Sie die Zeile, die auf die Funktion fetch_visits() verweist:

    @app.route('/', methods=['GET', 'POST'])
    def root():
        'main application (GET/POST) handler'
        context = {}
        if request.method == 'GET':
            context['upload_url'] = url_for('upload')
        else:
            context['visits'] = fetch_visits(10)
        return render_template('index.html', **context)
    
  6. Schließen Sie fetch_visits() in die Funktion etl_visits() ein. Beispiel:

    @app.route('/', methods=['GET', 'POST'])
    def root():
        'main application (GET/POST) handler'
        context = {}
        if request.method == 'GET':
            context['upload_url'] = url_for('upload')
        else:
            context['visits'] = etl_visits(fetch_visits(10)) # etl_visits wraps around fetch_visits
        return render_template('index.html', **context)
    

Beispiele

Nächste Schritte