Accédez à plus de 700 ateliers et cours

Développer des applications avec Google Cloud : stocker des données d'application

Atelier 1 heure 30 minutes universal_currency_alt 5 crédits show_chart Intermédiaire
info Cet atelier peut intégrer des outils d'IA pour vous accompagner dans votre apprentissage.
Accédez à plus de 700 ateliers et cours

Présentation

Les bibliothèques clientes Cloud sont la méthode recommandée pour appeler les API Google Cloud à partir de vos applications. Elles utilisent les conventions et le style naturels du langage de programmation dont vous vous servez pour votre application. Les bibliothèques clientes Cloud gèrent la communication de bas niveau avec le serveur, y compris l'authentification et la logique de nouvelle tentative.

Conçu pour le scaling automatique et les hautes performances, Firestore est une base de données de documents NoSQL sans serveur, entièrement gérée et rapide qui simplifie le développement d'applications.

Cloud Storage est une solution unifiée de stockage d'objets qui permet de diffuser, d'analyser et d'archiver des données partout dans le monde.

Dans cet atelier, vous allez créer une application Python qui gère une liste de livres. Vous pouvez ajouter, modifier et supprimer des livres, et collecter des données telles que l'auteur, le titre et la description. L'application initiale stocke les données dans un dictionnaire Python en mémoire, ce qui entraîne la perte de tous les livres lorsque l'application plante.

Vous allez modifier cette application pour stocker toutes les données des livres dans Firestore, puis ajouter la possibilité de stocker une image de couverture pour un livre, que vous allez conserver dans Cloud Storage.

Objectifs de l'atelier

Dans cet atelier, vous apprendrez à effectuer les tâches suivantes :

  • Créer une application Web Python Flask simple
  • Créer une base de données Firestore pour stocker les données de l'application
  • Créer un bucket Cloud Storage pour stocker les images à utiliser dans l'application

Préparation

Pour chaque atelier, nous vous attribuons un nouveau projet Google Cloud et un nouvel ensemble de ressources pour une durée déterminée, sans frais.

  1. Cliquez sur le bouton Démarrer l'atelier. Si l'atelier est payant, un pop-up s'affiche pour vous permettre de sélectionner un mode de paiement. Sur la gauche, vous trouverez le panneau Détails concernant l'atelier, qui contient les éléments suivants :

    • Le bouton Ouvrir la console Google Cloud
    • Le temps restant
    • Les identifiants temporaires que vous devez utiliser pour cet atelier
    • Des informations complémentaires vous permettant d'effectuer l'atelier
  2. Cliquez sur Ouvrir la console Google Cloud (ou effectuez un clic droit et sélectionnez Ouvrir le lien dans la fenêtre de navigation privée si vous utilisez le navigateur Chrome).

    L'atelier lance les ressources, puis ouvre la page Se connecter dans un nouvel onglet.

    Conseil : Réorganisez les onglets dans des fenêtres distinctes, placées côte à côte.

    Remarque : Si la boîte de dialogue Sélectionner un compte s'affiche, cliquez sur Utiliser un autre compte.
  3. Si nécessaire, copiez le nom d'utilisateur ci-dessous et collez-le dans la boîte de dialogue Se connecter.

    {{{user_0.username | "Username"}}}

    Vous trouverez également le nom d'utilisateur dans le panneau Détails concernant l'atelier.

  4. Cliquez sur Suivant.

  5. Copiez le mot de passe ci-dessous et collez-le dans la boîte de dialogue Bienvenue.

    {{{user_0.password | "Password"}}}

    Vous trouverez également le mot de passe dans le panneau Détails concernant l'atelier.

  6. Cliquez sur Suivant.

    Important : Vous devez utiliser les identifiants fournis pour l'atelier. Ne saisissez pas ceux de votre compte Google Cloud. Remarque : Si vous utilisez votre propre compte Google Cloud pour cet atelier, des frais supplémentaires peuvent vous être facturés.
  7. Accédez aux pages suivantes :

    • Acceptez les conditions d'utilisation.
    • N'ajoutez pas d'options de récupération ni d'authentification à deux facteurs (ce compte est temporaire).
    • Ne vous inscrivez pas à des essais sans frais.

Après quelques instants, la console Cloud s'ouvre dans cet onglet.

Remarque : Pour afficher un menu contenant la liste des produits et services Google Cloud, cliquez sur le menu de navigation en haut à gauche, ou saisissez le nom du service ou du produit dans le champ Recherche. Icône du menu de navigation

Activer Google Cloud Shell

Google Cloud Shell est une machine virtuelle qui contient de nombreux outils pour les développeurs. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud.

Google Cloud Shell vous permet d'accéder à vos ressources Google Cloud grâce à une ligne de commande.

  1. Dans la barre d'outils située en haut à droite dans la console Cloud, cliquez sur le bouton "Ouvrir Cloud Shell".

    Icône Cloud Shell encadrée

  2. Cliquez sur Continuer.

Le provisionnement et la connexion à l'environnement prennent quelques instants. Une fois connecté, vous êtes en principe authentifié et le projet est défini sur votre ID_PROJET. Par exemple :

ID de projet mis en évidence dans le terminal Cloud Shell

gcloud est l'outil de ligne de commande pour Google Cloud. Il est préinstallé sur Cloud Shell et permet la complétion par tabulation.

  • Vous pouvez lister les noms des comptes actifs à l'aide de cette commande :
gcloud auth list

Résultat :

Credentialed accounts: - @.com (active)

Exemple de résultat :

Credentialed accounts: - google1623327_student@qwiklabs.net
  • Vous pouvez lister les ID de projet à l'aide de cette commande :
gcloud config list project

Résultat :

[core] project =

Exemple de résultat :

[core] project = qwiklabs-gcp-44776a13dea667a6 Remarque : Pour consulter la documentation complète sur gcloud, accédez au guide de présentation de la gcloud CLI.

Tâche 1 : Créer et tester une application Web Python Flask simple

Dans cette tâche, vous allez créer et tester une application Python qui stocke une liste de livres.

Remarque : Dans la plupart des langages, le retrait est utilisé pour rendre le code plus lisible. En Python, le retrait sert à indiquer un bloc de code. Il doit donc être correct. Le nombre d'espaces de retrait doit être cohérent. Utiliser à la fois des espaces et des tabulations comme indicateurs de retrait peut également entraîner des problèmes. Dans cet atelier, un retrait en Python correspond à une série de quatre espaces.

Confirmer que Cloud Shell est autorisé

  1. Pour vérifier si Cloud Shell est autorisé, exécutez la commande suivante dans Cloud Shell :

    gcloud auth list
  2. Si vous êtes invité à autoriser Cloud Shell, cliquez sur Autoriser.

Créer le répertoire de l'application

Pour créer le répertoire de l'application, exécutez la commande suivante :

mkdir ~/bookshelf

Les fichiers de l'application sont créés dans le répertoire ~/bookshelf.

Spécifier et installer les éléments requis

Un fichier d'exigences Python est un fichier texte simple qui contient la liste des dépendances nécessaires à votre projet. Pour commencer, nous avons besoin de trois modules dans notre fichier d'exigences.

Notre application est écrite avec Flask, un module de framework Web qui permet de concevoir facilement des applications Web en Python. Nous exécutons l'application à l'aide de Gunicorn, un serveur HTTP Python qui s'exécute sous Linux. Enfin, nous consignons les informations concernant notre application à l'aide de Cloud Logging.

  1. Pour créer le fichier requirements, exécutez la commande suivante :

    cat > ~/bookshelf/requirements.txt <<EOF Flask==2.3.3 gunicorn==21.2.0 google-cloud-logging==3.6.0 EOF

    Le fichier requirements.txt spécifie les versions de Flask, Gunicorn et Google Cloud Logging utilisées par l'application.

  2. Pour installer les versions sélectionnées des dépendances, exécutez la commande suivante :

    pip3 install -r ~/bookshelf/requirements.txt --user

    pip est le programme d'installation de packages pour Python. La commande pip3 installe les packages spécifiés dans le fichier requirements.txt qui doivent être utilisés avec Python 3.

Créer l'implémentation de la base de données de livres

  1. Pour créer le code de la base de données de livres, exécutez la commande suivante :

    cat > ~/bookshelf/booksdb.py <<EOF db = {} # global in-memory python dictionary, key should always be a string next_id = 1 # next book ID to use def get_next_id(): """ Return the next ID. Automatically increments when retrieving one. """ global next_id id = next_id # next ID is 1 higher next_id = next_id + 1 # return a string version of the ID return str(id) def read(book_id): """ Return the details for a single book. """ # retrieve a book from the database by ID data = db[str(book_id)] return data def create(data): """ Create a new book and return the book details. """ # get a new ID for the book book_id = get_next_id() # set the ID in the book data data['id'] = book_id # store book in database db[book_id] = data return data def update(data, book_id): """ Update an existing book, and return the updated book's details. """ # book ID should always be a string book_id_str = str(book_id) # add ID to the book data data['id'] = book_id_str # update book in the database db[book_id_str] = data return data def delete(book_id): """ Delete a book in the database. """ # remove book from database del db[str(book_id)] # no return required def list(): """ Return a list of all books in the database. """ # empty list of books books = [] # retrieve each item in database and add to the list for k in db: books.append(db[k]) # return the list return books EOF

    Les livres sont stockés dans un dictionnaire Python, une structure de données permettant de stocker des paires clé/valeur. La clé doit être unique. La fonction get_next_id() crée donc un ID à chaque appel.

    La fonction read(book_id) récupère l'élément correspondant à la clé book_id fournie.

    La fonction create(data) ajoute le livre à la base de données en obtenant un nouvel ID, en stockant cet ID dans les données du livre, puis en stockant l'entrée de données dans le dictionnaire.

    La fonction update(data, book_id) met à jour le livre dans la base de données en stockant l'ID fourni dans les données du livre, puis en stockant l'entrée de données dans le dictionnaire.

    La fonction delete(book_id) supprime l'entrée de la base de données correspondant à la clé book_id fournie.

    La fonction list() renvoie une liste Python contenant tous les livres de la base de données. Pour obtenir cette liste, elle passe en revue le dictionnaire et récupère chaque élément. Chaque élément stocke son ID à l'aide de la clé id.

Créer les fichiers de modèle HTML

Les modèles sont des fichiers qui contiennent à la fois des données statiques et des espaces réservés pour les données dynamiques. Vous générez un modèle pour produire un fichier HTML final.

  1. Pour créer le modèle de base, exécutez la commande suivante :

    mkdir ~/bookshelf/templates cat > ~/bookshelf/templates/base.html <<EOF <!DOCTYPE html> <html lang="en"> <head> <title>Bookshelf</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"> </head> <body> <div class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <div class="navbar-brand">Bookshelf</div> </div> <ul class="nav navbar-nav"> <li><a href="/">Books</a></li> </ul> </div> </div> <div class="container"> {% block content %}{% endblock %} </div> </body> </html> EOF

    Toutes les pages de l'application disposent de la même mise en page de base, mais leur corps est différent. Chacun des trois modèles principaux (liste, vue, formulaire) étend ce modèle de base en spécifiant le contenu à placer au centre de la page.

  2. Pour créer le modèle de liste, exécutez la commande suivante :

    cat > ~/bookshelf/templates/list.html <<EOF {% extends "base.html" %} {% block content %} <h3>Books</h3> <a href="/books/add" class="btn btn-success btn-sm"> <i class="glyphicon glyphicon-plus"></i> Add book </a> {% for book in books %} <div class="media"> <a href="/books/{{book.id}}"> <div class="media-body"> <h4>{{book.title}}</h4> <p>{{book.author}}</p> </div> </a> </div> {% else %} <p>No books found</p> {% endfor %} {% endblock %} EOF

    Le modèle de liste parcourt la liste des livres envoyés au modèle de base et affiche le titre, l'auteur et le lien de chaque livre. Le lien permet à l'utilisateur d'accéder à la page de vue du livre.

  3. Pour créer le modèle de vue, exécutez la commande suivante :

    cat > ~/bookshelf/templates/view.html <<EOF {% extends "base.html" %} {% block content %} <h3>Book</h3> <div class="btn-group"> <a href="/books/{{book.id}}/edit" class="btn btn-primary btn-sm"> <i class="glyphicon glyphicon-edit"></i> Edit book </a> <a href="/books/{{book.id}}/delete" class="btn btn-danger btn-sm"> <i class="glyphicon glyphicon-trash"></i> Delete book </a> </div> <div class="media"> <div class="media-body"> <h4 class="book-title"> {{book.title}} <small>{{book.publishedDate}}</small> </h4> <h5 class="book-author">By {{book.author|default('Unknown', True)}}</h5> <p class="book-description">{{book.description}}</p> </div> </div> {% endblock %} EOF

    Le modèle de vue affiche les détails du livre (titre, auteur, date de publication et description). Il comporte également deux boutons : l'un pour modifier le livre (redirige l'utilisateur vers le modèle de formulaire) et l'autre pour le supprimer (supprime le livre et redirige l'utilisateur vers la liste des livres).

  4. Pour créer le modèle de formulaire, exécutez la commande suivante :

    cat > ~/bookshelf/templates/form.html <<EOF {# [START form] #} {% extends "base.html" %} {% block content %} <h3>{{action}} book</h3> <form method="POST" enctype="multipart/form-data"> <div class="form-group"> <label for="title">Title</label> <input type="text" name="title" id="title" value="{{book.title}}" class="form-control"/> </div> <div class="form-group"> <label for="author">Author</label> <input type="text" name="author" id="author" value="{{book.author}}" class="form-control"/> </div> <div class="form-group"> <label for="publishedDate">Date Published</label> <input type="text" name="publishedDate" id="publishedDate" value="{{book.publishedDate}}" class="form-control"/> </div> <div class="form-group"> <label for="description">Description</label> <textarea name="description" id="description" class="form-control">{{book.description}}</textarea> </div> <button type="submit" class="btn btn-success">Save</button> </form> {% endblock %} {# [END form] #} EOF

    Le modèle de formulaire a une double finalité. Lorsque vous mettez à jour un livre, le modèle affiche les détails du livre actuel dans des zones modifiables. Lorsque vous cliquez sur le bouton Enregistrer, les champs du formulaire mis à jour sont enregistrés dans la base de données.

    Lorsque vous créez un livre, les zones de détails du livre sont vides. Lorsque vous cliquez sur le bouton Enregistrer, les données du livre sont enregistrées dans la base de données en tant que nouveau livre.

Créer le fichier de code principal

  1. Pour créer le fichier de code principal, exécutez la commande suivante :

    cat > ~/bookshelf/main.py <<EOF from flask import current_app, Flask, redirect, render_template from flask import request, url_for import logging from google.cloud import logging as cloud_logging import booksdb app = Flask(__name__) app.config.update( SECRET_KEY='secret', # don't store SECRET_KEY in code in a production app MAX_CONTENT_LENGTH=8 * 1024 * 1024, ) app.debug = True app.testing = False # configure logging if not app.testing: logging.basicConfig(level=logging.INFO) # attach a Cloud Logging handler to the root logger client = cloud_logging.Client() client.setup_logging() def log_request(req): """ Log request """ current_app.logger.info('REQ: {0} {1}'.format(req.method, req.url)) @app.route('/') def list(): """ Display all books. """ log_request(request) # get list of books books = booksdb.list() # render list of books return render_template('list.html', books=books) @app.route('/books/<book_id>') def view(book_id): """ View the details of a specified book. """ log_request(request) # retrieve a specific book book = booksdb.read(book_id) # render book details return render_template('view.html', book=book) @app.route('/books/add', methods=['GET', 'POST']) def add(): """ If GET, show the form to collect details of a new book. If POST, create the new book based on the specified form. """ log_request(request) # Save details if form was posted if request.method == 'POST': # get book details from form data = request.form.to_dict(flat=True) # add book book = booksdb.create(data) # render book details return redirect(url_for('.view', book_id=book['id'])) # render form to add book return render_template('form.html', action='Add', book={}) @app.route('/books/<book_id>/edit', methods=['GET', 'POST']) def edit(book_id): """ If GET, show the form to collect updated details for a book. If POST, update the book based on the specified form. """ log_request(request) # read existing book details book = booksdb.read(book_id) # Save details if form was posted if request.method == 'POST': # get book details from form data = request.form.to_dict(flat=True) # update book book = booksdb.update(data, book_id) # render book details return redirect(url_for('.view', book_id=book['id'])) # render form to update book return render_template('form.html', action='Edit', book=book) @app.route('/books/<book_id>/delete') def delete(book_id): """ Delete the specified book and return to the book list. """ log_request(request) # delete book booksdb.delete(book_id) # render list of remaining books return redirect(url_for('.list')) # this is only used when running locally if __name__ == '__main__': app.run(host='127.0.0.1', port=8080, debug=True) EOF

    Le fichier main.py est le point d'entrée de l'application. Il implémente l'application Flask, qui spécifie le routage des URL Web, génère les modèles et gère la base de données de livres. N'hésitez pas à examiner le code, qui est bien commenté.

Tester l'application

  1. Pour vérifier le contenu du répertoire "bookshelf", exécutez la commande suivante :

    cd ~ ls -R bookshelf

    Vous devriez voir une liste contenant deux fichiers Python, un fichier d'exigences et quatre fichiers de modèle :

    bookshelf: booksdb.py main.py requirements.txt templates bookshelf/templates: base.html form.html list.html view.html
  2. Pour exécuter le serveur HTTP Gunicorn, exécutez la commande suivante :

    cd ~/bookshelf; ~/.local/bin/gunicorn -b :8080 main:app

    Si vous avez réussi à créer les fichiers, l'application doit maintenant être hébergée sur le port 8080.

  3. Pour exécuter l'application dans le navigateur Web, cliquez sur Aperçu sur le Web, puis sélectionnez Prévisualiser sur le port 8080.

    Aperçu sur le Web sur le port 8080

    Un nouvel onglet s'ouvre dans le navigateur et l'application s'exécute. Il s'agit de l'URL racine, qui affiche la liste de tous les livres existants. Elle est vide pour l'instant.

    Remarque : Si un message vous demande d'autoriser Cloud Shell, cliquez sur Autoriser.
  4. Dans l'onglet de l'application, cliquez sur + Ajouter un livre.

  5. Saisissez le titre, l'auteur, la date et la description d'un livre, réel ou fictif, puis cliquez sur Enregistrer.

    Vous revenez à la page de vue, qui contient les détails du livre. Vous pouvez modifier ou supprimer le livre en cliquant sur le bouton approprié.

  6. En haut de la page, cliquez sur Livres.

    Vous revenez à la page de vue. Tous les livres que vous avez ajoutés s'affichent dans la liste.

    Si vous le souhaitez, vous pouvez parcourir l'application pour ajouter, modifier ou supprimer des livres.

  7. Dans Cloud Shell, pour quitter l'application, appuyez sur Ctrl+C.

Cliquez sur Vérifier ma progression pour valider l'objectif. Créer et tester une application Web Python Flask simple

Tâche 2 : Utiliser Firestore pour la base de données de livres

Dans cette tâche, vous allez stocker les données des livres à l'aide d'une base de données Firestore.

L'application utilise actuellement un dictionnaire Python en mémoire. Les livres sont perdus dès que l'application se ferme ou plante. Il est préférable d'utiliser Firestore pour la base de données persistante.

Créer la base de données Firestore

  1. Dans le menu de navigation (Icône du menu de navigation), accédez à Afficher tous les produits > Bases de données.

  2. Cliquez sur l'icône Épingler à côté de Firestore pour l'ajouter au menu de navigation, puis sur Firestore.

  3. Cliquez sur Créer une base de données Firestore.

  4. Dans Options de configuration, sélectionnez Firestore natif.

  5. Pour Type d'emplacement, cliquez sur Région.

    Dans cet atelier, vous ne devez pas utiliser le type d'emplacement Multirégional pour Firestore.

  6. Pour Région, sélectionnez , puis cliquez sur Créer une base de données.

    Remarque : La région exacte doit être sélectionnée pour l'emplacement. Si vous ne voyez pas cette région dans la liste déroulante, vérifiez que vous avez bien sélectionné Région (et non "Multirégional") pour Type d'emplacement.

    Si aucune région n'est disponible dans la liste déroulante, annulez l'opération et revenez à la page précédente, puis réessayez d'effectuer le processus de création de la base de données.

    La création de la base de données peut prendre quelques minutes. Lorsque vous ajoutez un document à une collection, elle est automatiquement créée dans Firestore. Vous n'avez donc pas besoin de créer une collection de livres pour l'instant.

    La création de la base de données Firestore active l'API Firestore.

Modifier l'application afin d'exiger le client Python pour Firestore

Le client Python pour l'API Firestore permet d'accéder aux données Firestore depuis vos applications. Le nom du package de ce client est google-cloud-firestore, et la version à utiliser est 2.12.0.

  1. Modifiez l'application pour exiger la version 2.12.0 du package google-cloud-firestore.
Remarque : Vous pouvez utiliser l'éditeur de fichiers de votre choix, y compris nano, vi et l'éditeur Cloud Code.
  1. Pour installer la dépendance mise à jour, exécutez la commande suivante :

    pip3 install -r ~/bookshelf/requirements.txt --user

Modifier l'application pour stocker les données des livres dans Firestore

Maintenant que l'application exige le package google-cloud-firestore, vous pouvez l'utiliser dans l'implémentation de la base de données de livres.

Avec Firestore, les données des livres sont stockées dans la base de données Firestore. Si vos données comportent un champ unique garanti pouvant servir d'ID, vous pouvez choisir de l'utiliser comme ID dans Firestore. Dans le cas présent, les données que vous utilisez n'ont pas de champ unique. Firestore peut créer automatiquement l'ID lorsque vous créez un livre.

Voici un exemple d'utilisation du client Firestore :

from google.cloud import firestore # get the client db = firestore.Client() # create a new document data = {"name": "Sue", "role": "treasurer"} member_ref = db.collection("members").document() member_ref.set(data) member_id = member_ref.get().id # retrieve a document member_ref = db.collection("members").document(member_id) member = member_ref.get() if member.exists: print(f"Document data: {member.to_dict()}") else: print("Member not found.") # update a document new_data = {"name": "Sue", "role": "president"} member_ref = db.Collection("members").document(member_id) member_ref.set(new_data) # get all documents in order members = db.collection("members").order_by("name").stream() for member in members: print(f"{member.id} => {member.to_dict()}") # delete a member member_ref = db.Collection("members").document(member_id) member_ref.delete()

Vous allez ensuite modifier l'implémentation de la base de données de livres pour utiliser Firestore.

Remarque : N'oubliez pas que quatre espaces sont nécessaires pour le retrait en Python.

L'implémentation actuelle utilise une variable globale nommée db, qui est un dictionnaire Python en mémoire. Elle utilise également la variable next_id et la fonction get_next_id(), qui crée les ID des éléments stockés dans le dictionnaire.

Firestore gère la création des ID pour vous. Utilisez une collection nommée books. Vous devez ajouter l'ID créé au dictionnaire Python qui contient les détails d'un livre avant de le renvoyer à l'appelant.

Remarque : Les indices masquent les modifications à apporter au code. Vous pouvez essayer d'écrire le code vous-même ou cliquer sur les boutons d'indice pour obtenir le code à ajouter.
  1. Dans un éditeur de fichiers, ouvrez le fichier ~/bookshelf/booksdb.py.

  2. Supprimez les lignes suivantes du fichier :

    db = {} # global in-memory python dictionary, key should always be a string next_id = 1 # next book ID to use def get_next_id(): """ Return the next ID. Automatically increments when retrieving one. """ global next_id id = next_id # next ID is 1 higher next_id = next_id + 1 # return a string version of the ID return str(id)

    La base de données en mémoire et la fonctionnalité de création d'ID ne sont pas nécessaires dans cette implémentation.

  3. Ajoutez du code qui importe le client Firestore.

  1. Créez une fonction qui convertit un document Firestore en dictionnaire.

Il ne faut pas que l'appelant ait à interpréter les documents Firestore lorsque vous lui renvoyez un livre. Les interfaces des fonctions de la base de données de livres doivent rester inchangées. Cette implémentation continue donc à renvoyer et à accepter des livres sous forme de dictionnaires Python.

Avant qu'un livre soit renvoyé, son ID doit être ajouté au dictionnaire.

Créez une fonction nommée document_to_dict() qui prend un document Firestore comme paramètre d'entrée et renvoie un dictionnaire. Le dictionnaire inclut les paires clé/valeur dans le document et renvoie également l'ID du document comme valeur de la clé id. Si le document n'existe pas, vous devez renvoyer None.

  1. Modifiez la fonction read() pour récupérer un livre dans la collection books de Firestore. Votre fonction mise à jour doit appeler la fonction document_to_dict().
  1. Modifiez la fonction create() pour créer un livre dans la collection books de Firestore.
  1. Modifiez la fonction update() pour mettre à jour un livre dans la collection books de Firestore.
  1. Modifiez la fonction delete() pour supprimer un livre dans la collection books de Firestore.
  1. Modifiez la fonction list() pour renvoyer une liste de tous les livres triés par titre de la collection books de Firestore.

Et voilà ! En mettant à jour le fichier booksdb.py, vous modifiez l'application pour qu'elle utilise Firestore comme base de données sans avoir à modifier le code d'appel.

Tester l'application mise à jour

  1. Dans Cloud Shell, exécutez la commande suivante :

    cd ~/bookshelf; ~/.local/bin/gunicorn -b :8080 main:app

    Si vous avez réussi à mettre à jour les fichiers, l'application doit maintenant être hébergée sur le port 8080.

    Remarque : Si vous recevez une erreur d'importation, vérifiez que vous avez utilisé pip3 pour installer les éléments requis, qui ont été mis à jour et incluent désormais le package google.cloud.firestore. Remarque : Si un message vous demande d'autoriser Cloud Shell, cliquez sur Autoriser.
  2. Pour exécuter l'application dans le navigateur Web, cliquez sur Aperçu sur le Web, puis sélectionnez Prévisualiser sur le port 8080.

    Il n'y a aucun livre dans la base de données, car les livres étaient stockés dans un dictionnaire en mémoire.

  3. Dans l'onglet de l'application, cliquez sur + Ajouter un livre.

  4. Saisissez les informations suivantes dans le formulaire :

    Champ Valeur
    Titre Hamlet
    Auteur William Shakespeare
    Date de publication 1603
    Description Un prince médite sur la vie, la mort et la vengeance, mais il fait surtout des jeux de mots.
  5. Cliquez sur Enregistrer.

    Vous revenez à la page de vue, qui contient les détails du livre.

  6. En haut de la page, cliquez sur Livres.

    Vous êtes redirigé vers la page de la liste, dans laquelle figure Hamlet.

    Remarque : Vous pouvez ajouter des livres si vous le souhaitez, mais ne modifiez pas Hamlet, car vous en aurez besoin dans la tâche suivante.
  7. Dans la console Google Cloud, accédez au menu de navigation (Icône du menu de navigation), puis cliquez sur Firestore.

    Remarque : Même si vous êtes déjà sur la page de la console Firestore, vous devrez peut-être y accéder à nouveau pour voir la base de données.
  8. Cliquez sur (par défaut).

    Vous devriez voir qu'un document a été créé pour Hamlet dans la collection books.

  9. Dans Cloud Shell, pour quitter l'application, appuyez sur Ctrl+C.

Résoudre les problèmes rencontrés lors de la tâche 2

Les erreurs survenues dans votre application sont actuellement affichées dans Cloud Shell. Si l'application ne fonctionne pas ou n'enregistre pas les données dans Firestore, utilisez les informations sur les erreurs pour déboguer et résoudre le problème.

Si vous avez des difficultés à faire fonctionner le code de la base de données de livres, la commande fournie dans l'indice suivant permet de remplacer l'intégralité du fichier booksdb.py par un code opérationnel.

Cliquez sur Vérifier ma progression pour valider l'objectif. Utiliser Firestore pour la base de données de livres

Tâche 3 : Utiliser Cloud Storage pour les couvertures de livre

Dans cette tâche, vous allez utiliser Cloud Storage pour stocker des images de couverture de livre.

Une base de données n'est généralement pas l'emplacement approprié pour stocker des images. Vous ne pouvez pas stocker de fichiers dans Cloud Shell, car vous devrez héberger l'application ailleurs ultérieurement. Cloud Storage est la solution idéale pour stocker les éléments que vous souhaitez partager. Il s'agit du principal store d'objets pour Google Cloud.

Créer le bucket Cloud Storage

Pour utiliser Cloud Storage, vous devez créer un bucket Cloud Storage, qui est un conteneur de base permettant de conserver vos données.

  1. Dans la console Google Cloud, accédez au menu de navigation (Icône du menu de navigation) et cliquez sur Cloud Storage > Buckets.

  2. Cliquez sur + Créer.

  3. Pour le nom du bucket, utilisez le code suivant :

    {{{ project_0.project_id | project_id }}}-covers
  4. Cliquez sur Continuer.

  5. Sélectionnez Région.

  6. Sélectionnez .

  7. Cliquez sur Continuer.

  8. Laissez la classe de stockage inchangée, puis cliquez sur Continuer.

  9. Décochez la case Appliquer la protection contre l'accès public sur ce bucket.

    Laissez le Contrôle des accès défini sur Uniforme. Cette option permet d'utiliser des autorisations au niveau du bucket pour tous les objets ajoutés au bucket.

  10. Cliquez sur Créer.

    Pour que les couvertures soient visibles dans l'application, vous devez autoriser tous les utilisateurs à lire les objets du bucket.

  11. Sélectionnez l'onglet Autorisations, puis cliquez sur Accorder l'accès.

  12. Dans le champ Nouveaux comptes principaux, saisissez allUsers.

  13. Pour le rôle, sélectionnez Anciens rôles Cloud Storage > Lecteur des anciens objets de l'espace de stockage.

    Remarque : Le rôle Cloud Storage > Lecteur d'objets Storage inclut l'autorisation permettant de lister les objets d'un bucket, ce qui n'est pas nécessaire pour cette application. Le rôle Anciens rôles Cloud Storage > Lecteur des anciens objets de l'espace de stockage ne permet que de récupérer des objets, ce qui est plus approprié pour ce cas d'utilisation.
  14. Cliquez sur Enregistrer.

  15. Si un message vous demande de confirmer l'opération, cliquez sur Autoriser l'accès public.

Mettre à jour le fichier d'exigences

  1. Dans Cloud Shell, utilisez un éditeur de fichiers pour ouvrir ~/bookshelf/requirements.txt.

  2. Dans le fichier ~/bookshelf/requirements.txt, ajoutez la ligne suivante :

    google-cloud-storage==2.10.0

    Le fichier requirements.txt devrait maintenant se présenter comme suit :

    Flask==2.3.3 gunicorn==21.2.0 google-cloud-logging==3.6.0 google-cloud-firestore==2.12.0 google-cloud-storage==2.10.0
  3. Enregistrez le fichier.

  4. Pour installer la dépendance mise à jour, exécutez la commande suivante dans Cloud Shell :

    pip3 install -r ~/bookshelf/requirements.txt --user

Créer un code qui importe des images dans Cloud Storage

Le fichier storage.py contient le code permettant d'importer une image de couverture dans Cloud Storage.

  1. Pour créer le fichier storage.py, exécutez la commande suivante :

    cat > ~/bookshelf/storage.py <<EOF from __future__ import absolute_import import datetime import os from flask import current_app from werkzeug.exceptions import BadRequest from werkzeug.utils import secure_filename from google.cloud import storage def _check_extension(filename, allowed_extensions): """ Validates that the filename's extension is allowed. """ _, ext = os.path.splitext(filename) if (ext.replace('.', '') not in allowed_extensions): raise BadRequest( '{0} has an invalid name or extension'.format(filename)) def _safe_filename(filename): """ Generates a safe filename that is unlikely to collide with existing objects in Cloud Storage. filename.ext is transformed into filename-YYYY-MM-DD-HHMMSS.ext """ filename = secure_filename(filename) date = datetime.datetime.utcnow().strftime("%Y-%m-%d-%H%M%S") basename, extension = filename.rsplit('.', 1) return "{0}-{1}.{2}".format(basename, date, extension) def upload_file(file_stream, filename, content_type): """ Uploads a file to a given Cloud Storage bucket and returns the public url to the new object. """ _check_extension(filename, current_app.config['ALLOWED_EXTENSIONS']) filename = _safe_filename(filename) # build the name of the bucket bucket_name = os.getenv('GOOGLE_CLOUD_PROJECT') + '-covers' client = storage.Client() # create a bucket object bucket = client.bucket(bucket_name) # create an object in the bucket for the specified path blob = bucket.blob(filename) # upload the contents of the string into the object blob.upload_from_string( file_stream, content_type=content_type) # get the public URL for the object, which is used for storing a reference # to the image in the database and displaying the image in the app url = blob.public_url return url def upload_image(img): """ Upload the user-uploaded file to Cloud Storage and retrieve its publicly accessible URL. """ if not img: return None public_url = upload_file( img.read(), img.filename, img.content_type ) return public_url EOF

    La fonction upload_file() accepte un flux de fichier, un nom de fichier et le type de contenu du fichier. L'extension du nom de fichier est d'abord validée par rapport à une liste d'extensions approuvées qui sera créée lors d'une étape ultérieure. La date et l'heure actuelles sont ensuite ajoutées au nom de fichier, afin d'éviter les conflits entre des images de livre qui utilisent le même nom de fichier lors de l'importation. Le reste de la fonction interagit avec Cloud Storage.

    Le nom du bucket est d'abord créé à l'aide de l'ID du projet :

    bucket_name = os.getenv('GOOGLE_CLOUD_PROJECT') + '-covers'

    Ensuite, une référence à un objet est créée pour le bucket et le nom de fichier spécifiés, et le contenu du fichier image est importé :

    client = storage.Client() # create a bucket object bucket = client.bucket(bucket_name) # create an object in the bucket for the specified path blob = bucket.blob(filename)

    Les données du fichier sont ensuite importées dans Cloud Storage, et le fichier est rendu public afin de pouvoir être affiché dans l'application Web :

    # upload the contents of the string into the object blob.upload_from_string( file_stream, content_type=content_type)

    L'URL est ensuite renvoyée afin de pouvoir être stockée dans la base de données de livres et utilisée pour afficher l'image.

Modifier les modèles pour afficher des images de livre

Un modèle est affiché avec des données spécifiques pour produire une page Web.

Le modèle de base n'a pas besoin d'être modifié, mais les modèles de contenu (formulaire, liste, vue) doivent l'être pour afficher et importer les couvertures de livre.

  1. Dans un éditeur de fichiers, ouvrez le fichier ~/bookshelf/templates/form.html.

    Le formulaire doit être modifié pour collecter le fichier image.

  2. En bas du formulaire, au-dessus du bouton Enregistrer, ajoutez les lignes suivantes :

    <div class="form-group"> <label for="image">Cover Image</label> <input type="file" name="image" id="image" class="form-control"/> </div> <div class="form-group hidden"> <label for="imageUrl">Cover Image URL</label> <input type="text" name="imageUrl" id="imageUrl" value="{{book.imageUrl}}" class="form-control"/> </div>

    L'entrée image permet à l'utilisateur d'importer un fichier image et affiche l'image actuelle. L'entrée imageUrl est masquée, mais elle stocke l'URL publique de l'image, qui est ajoutée à l'entrée de la base de données pour le livre.

    Voici à quoi doit maintenant ressembler le formulaire :

    <form method="POST" enctype="multipart/form-data"> <div class="form-group"> <label for="title">Title</label> <input type="text" name="title" id="title" value="{{book.title}}" class="form-control"/> </div> <div class="form-group"> <label for="author">Author</label> <input type="text" name="author" id="author" value="{{book.author}}" class="form-control"/> </div> <div class="form-group"> <label for="publishedDate">Date Published</label> <input type="text" name="publishedDate" id="publishedDate" value="{{book.publishedDate}}" class="form-control"/> </div> <div class="form-group"> <label for="description">Description</label> <textarea name="description" id="description" class="form-control">{{book.description}}</textarea> </div> <div class="form-group"> <label for="image">Cover Image</label> <input type="file" name="image" id="image" class="form-control"/> </div> <div class="form-group hidden"> <label for="imageUrl">Cover Image URL</label> <input type="text" name="imageUrl" id="imageUrl" value="{{book.imageUrl}}" class="form-control"/> </div> <button type="submit" class="btn btn-success">Save</button> </form>
  3. Enregistrez le fichier.

  4. Dans un éditeur de fichiers, ouvrez le fichier ~/bookshelf/templates/view.html.

    L'image de livre doit s'afficher à gauche des informations sur le livre.

  5. Après la ligne <div class="media">, ajoutez les lignes suivantes :

    <div class="media-left"> {% if book.imageUrl %} <img class="book-image" src="{{book.imageUrl}}" width="128" height="192" alt="book cover"> {% else %} <img class="book-image" src="https://storage.googleapis.com/cloud-training/devapps-foundations/no-cover.png" width="128" height="192" alt="no book cover"> {% endif %} </div>

    Une nouvelle section est ajoutée à gauche des détails du livre. Si l'image de livre existe, elle apparaît dans cette section. Sinon, une image d'espace réservé s'affiche à la place.

    L'élément div media se présente désormais comme suit :

    <div class="media"> <div class="media-left"> {% if book.imageUrl %} <img class="book-image" src="{{book.imageUrl}}" width="128" height="192" alt="book cover"> {% else %} <img class="book-image" src="https://storage.googleapis.com/cloud-training/devapps-foundations/no-cover.png" width="128" height="192" alt="no book cover"> {% endif %} </div> <div class="media-body"> <h4 class="book-title"> {{book.title}} <small>{{book.publishedDate}}</small> </h4> <h5 class="book-author">By {{book.author|default('Unknown', True)}}</h5> <p class="book-description">{{book.description}}</p> </div> </div>
  6. Enregistrez le fichier.

  7. Dans un éditeur de fichiers, ouvrez le fichier ~/bookshelf/templates/list.html.

    L'image de livre doit maintenant s'afficher à gauche de chaque livre de la liste.

  8. Après la ligne <a href="/books/{{book.id}}">, ajoutez les lignes suivantes :

    <div class="media-left"> {% if book.imageUrl %} <img src="{{book.imageUrl}}" width="128" height="192" alt="book cover"> {% else %} <img src="https://storage.googleapis.com/cloud-training/devapps-foundations/no-cover.png" width="128" height="192" alt="no book cover"> {% endif %} </div>

    Elles contiennent le même code que celui que vous avez ajouté au modèle de vue.

Modifier le fichier main.py

Le fichier de code principal doit importer l'image dans Cloud Storage lorsque le formulaire est publié, et l'URL de l'image doit être ajoutée aux données du livre.

  1. Dans un éditeur de fichiers, ouvrez le fichier ~/bookshelf/main.py.

  2. Une fois booksdb importé, ajoutez la ligne suivante :

    import storage
  3. Après les lignes d'importation, ajoutez la méthode upload_image_file() :

    def upload_image_file(img): """ Upload the user-uploaded file to Cloud Storage and retrieve its publicly accessible URL. """ if not img: return None public_url = storage.upload_file( img.read(), img.filename, img.content_type ) current_app.logger.info( 'Uploaded file %s as %s.', img.filename, public_url) return public_url

    Cette fonction appelle la fonction de bibliothèque que vous avez créée dans storage.py pour importer le fichier de couverture dans Cloud Storage. Elle renvoie l'URL publique du fichier importé.

  4. Ajoutez la ligne suivante à la section app.config.update :

    ALLOWED_EXTENSIONS=set(['png', 'jpg', 'jpeg', 'gif']),

    Cela limite les extensions autorisées lors de l'importation d'une couverture de livre. Voici à quoi doit maintenant ressembler la configuration :

    app.config.update( SECRET_KEY='secret', MAX_CONTENT_LENGTH=8 * 1024 * 1024, ALLOWED_EXTENSIONS=set(['png', 'jpg', 'jpeg', 'gif']), )
  5. Dans la fonction add(), après la ligne data = request.form.to_dict(flat=True), ajoutez le code suivant :

    image_url = upload_image_file(request.files.get('image')) # If an image was uploaded, update the data to point to the image. if image_url: data['imageUrl'] = image_url

    Ce code appelle la fonction upload_image_file pour importer l'image qui a été ajoutée dans le formulaire. Il ajoute également l'URL de l'image aux données du livre.

  6. Dans la fonction edit(), après la ligne data = request.form.to_dict(flat=True), ajoutez le code suivant :

    image_url = upload_image_file(request.files.get('image')) # If an image was uploaded, update the data to point to the image. if image_url: data['imageUrl'] = image_url

    Il s'agit du même code que celui que vous avez ajouté à la fonction add().

  7. Enregistrez le fichier.

Tester l'application mise à jour

  1. Dans Cloud Shell, exécutez la commande suivante :

    cd ~/bookshelf; ~/.local/bin/gunicorn -b :8080 main:app

    Si vous avez réussi à mettre à jour les fichiers, l'application doit maintenant être hébergée sur le port 8080.

    Remarque : Si un message vous demande d'autoriser Cloud Shell, cliquez sur Autoriser.
  2. Pour exécuter l'application dans le navigateur Web, cliquez sur Aperçu sur le Web, puis sélectionnez Prévisualiser sur le port 8080.

    Les livres qui ont été ajoutés lorsque l'application utilisait Firestore doivent s'afficher. Chaque livre affiche l'image de couverture d'espace réservé, car les URL des images n'avaient pas été ajoutées à la base de données.

  3. Cliquez sur Hamlet, puis sur Modifier le livre.

  4. Effectuez un clic droit sur l'image de couverture du livre Hamlet, puis enregistrez-la sur votre ordinateur sous le nom hamlet.png :

    Couverture du livre Hamlet

  5. Dans l'application Bookshelf, pour Image de couverture, cliquez sur Sélectionner un fichier.

  6. Sélectionnez le fichier que vous avez téléchargé (hamlet.png), puis cliquez sur Ouvrir.

  7. Cliquez sur Enregistrer.

    L'image du livre Hamlet doit désormais s'afficher.

  8. Dans la console Google Cloud, accédez au menu de navigation (Icône du menu de navigation) et cliquez sur Cloud Storage > Buckets.

  9. Cliquez sur le nom du bucket (-covers).

    L'image de couverture est enregistrée dans Cloud Storage.

Cliquez sur Vérifier ma progression pour valider l'objectif. Utiliser Cloud Storage pour les couvertures de livre

Félicitations !

Vous avez réussi à tester une application dans Cloud Shell. Vous l'avez modifiée pour qu'elle utilise les bibliothèques clientes Cloud afin de stocker ses données dans Firestore et ses images dans Cloud Storage.

Étapes suivantes et informations supplémentaires

Terminer l'atelier

Une fois l'atelier terminé, cliquez sur Terminer l'atelier. Google Cloud Skills Boost supprime les ressources que vous avez utilisées, puis efface le compte.

Si vous le souhaitez, vous pouvez noter l'atelier. Sélectionnez un nombre d'étoiles, saisissez un commentaire, puis cliquez sur Envoyer.

Le nombre d'étoiles correspond à votre degré de satisfaction :

  • 1 étoile = très insatisfait(e)
  • 2 étoiles = insatisfait(e)
  • 3 étoiles = ni insatisfait(e), ni satisfait(e)
  • 4 étoiles = satisfait(e)
  • 5 étoiles = très satisfait(e)

Si vous ne souhaitez pas donner votre avis, vous pouvez fermer la boîte de dialogue.

Pour soumettre des commentaires, suggestions ou corrections, veuillez accéder à l'onglet Assistance.

Copyright 2024 Google LLC Tous droits réservés. Google et le logo Google sont des marques de Google LLC. Tous les autres noms de société et de produit peuvent être des marques des sociétés auxquelles ils sont associés.

Avant de commencer

  1. Les ateliers créent un projet Google Cloud et des ressources pour une durée déterminée.
  2. Les ateliers doivent être effectués dans le délai imparti et ne peuvent pas être mis en pause. Si vous quittez l'atelier, vous devrez le recommencer depuis le début.
  3. En haut à gauche de l'écran, cliquez sur Démarrer l'atelier pour commencer.

Utilisez la navigation privée

  1. Copiez le nom d'utilisateur et le mot de passe fournis pour l'atelier
  2. Cliquez sur Ouvrir la console en navigation privée

Connectez-vous à la console

  1. Connectez-vous à l'aide des identifiants qui vous ont été attribués pour l'atelier. L'utilisation d'autres identifiants peut entraîner des erreurs ou des frais.
  2. Acceptez les conditions d'utilisation et ignorez la page concernant les ressources de récupération des données.
  3. Ne cliquez pas sur Terminer l'atelier, à moins que vous n'ayez terminé l'atelier ou que vous ne vouliez le recommencer, car cela effacera votre travail et supprimera le projet.

Ce contenu n'est pas disponible pour le moment

Nous vous préviendrons par e-mail lorsqu'il sera disponible

Parfait !

Nous vous contacterons par e-mail s'il devient disponible

Un atelier à la fois

Confirmez pour mettre fin à tous les ateliers existants et démarrer celui-ci

Utilisez la navigation privée pour effectuer l'atelier

Ouvrez une fenêtre de navigateur en mode navigation privée pour effectuer cet atelier. Vous éviterez ainsi les conflits entre votre compte personnel et le compte temporaire de participant, qui pourraient entraîner des frais supplémentaires facturés sur votre compte personnel.