Cargando…
No se encontraron resultados.

02

Developing Applications with Google Cloud: Foundations

Obtén acceso a más de 700 labs y cursos

Desarrolla aplicaciones con Google Cloud: Almacenamiento de datos de aplicación

Lab 1 hora 30 minutos universal_currency_alt 5 créditos show_chart Intermedio
info Es posible que este lab incorpore herramientas de IA para facilitar tu aprendizaje.
Obtén acceso a más de 700 labs y cursos

Descripción general

Las bibliotecas cliente de Cloud son el método recomendado para llamar a las APIs de Google Cloud desde tus aplicaciones. Las bibliotecas cliente de Cloud usan las convenciones y el estilo naturales del lenguaje de programación que utilizas en tu aplicación. Las bibliotecas cliente de Cloud controlan la comunicación de bajo nivel con el servidor, incluida la autenticación y la lógica de reintentos.

Firestore es una base de datos NoSQL de documentos rápida, completamente administrada y sin servidores diseñada para el escalado automático, el alto rendimiento y la facilidad en el desarrollo de aplicaciones.

Cloud Storage es un almacenamiento de objetos unificado que te permite entregar, analizar y archivar datos en cualquier parte del mundo.

En este lab, crearás una aplicación de Python que administre una lista de libros. Puedes agregar, editar y borrar libros, y recopilar datos como autor, título y descripción. La aplicación inicial almacena los datos en un diccionario de Python en memoria, lo que hace que se pierdan todos los libros cuando falla la aplicación.

Modificarás esta aplicación para almacenar todos los datos del libro en Firestore y, luego, agregarás la capacidad de almacenar una imagen de portada para un libro, que persistirá en Cloud Storage.

Qué aprenderás

En este lab, aprenderás a realizar las siguientes tareas:

  • Crear una aplicación web simple con Flask para Python
  • Crear una base de datos de Firestore para almacenar los datos de aplicación
  • Crear un bucket de Cloud Storage para almacenar las imágenes que se usarán en la aplicación

Configuración y requisitos

En cada lab, recibirás un proyecto de Google Cloud y un conjunto de recursos nuevos por tiempo limitado y sin costo adicional.

  1. Haz clic en el botón Comenzar lab. Si debes pagar por el lab, se abrirá una ventana emergente para que selecciones tu forma de pago. A la izquierda, se encuentra el panel Detalles del lab, que tiene estos elementos:

    • El botón Abrir la consola de Google Cloud
    • El tiempo restante
    • Las credenciales temporales que debes usar para el lab
    • Otra información para completar el lab, si es necesaria
  2. Haz clic en Abrir la consola de Google Cloud (o haz clic con el botón derecho y selecciona Abrir el vínculo en una ventana de incógnito si ejecutas el navegador Chrome).

    El lab inicia recursos y abre otra pestaña en la que se muestra la página de acceso.

    Sugerencia: Ordena las pestañas en ventanas separadas, una junto a la otra.

    Nota: Si ves el diálogo Elegir una cuenta, haz clic en Usar otra cuenta.
  3. De ser necesario, copia el nombre de usuario a continuación y pégalo en el diálogo Acceder.

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

    También puedes encontrar el nombre de usuario en el panel Detalles del lab.

  4. Haz clic en Siguiente.

  5. Copia la contraseña que aparece a continuación y pégala en el diálogo Te damos la bienvenida.

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

    También puedes encontrar la contraseña en el panel Detalles del lab.

  6. Haz clic en Siguiente.

    Importante: Debes usar las credenciales que te proporciona el lab. No uses las credenciales de tu cuenta de Google Cloud. Nota: Usar tu propia cuenta de Google Cloud para este lab podría generar cargos adicionales.
  7. Haga clic para avanzar por las páginas siguientes:

    • Acepta los Términos y Condiciones.
    • No agregues opciones de recuperación o autenticación de dos factores (esta es una cuenta temporal).
    • No te registres para obtener pruebas gratuitas.

Después de un momento, se abrirá la consola de Google Cloud en esta pestaña.

Nota: Para ver un menú con una lista de productos y servicios de Google Cloud, haz clic en el menú de navegación que se encuentra en la parte superior izquierda o escribe el nombre del servicio o producto en el campo Búsqueda. Ícono del menú de navegación

Activa Google Cloud Shell

Google Cloud Shell es una máquina virtual que cuenta con herramientas para desarrolladores. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud.

Google Cloud Shell proporciona acceso de línea de comandos a tus recursos de Google Cloud.

  1. En la consola de Cloud, en la barra de herramientas superior derecha, haz clic en el botón Abrir Cloud Shell.

    Ícono de Cloud Shell destacado

  2. Haz clic en Continuar.

El aprovisionamiento y la conexión al entorno demorarán unos minutos. Cuando te conectes, habrás completado la autenticación, y el proyecto estará configurado con tu PROJECT_ID. Por ejemplo:

ID del proyecto destacado en la terminal de Cloud Shell

gcloud es la herramienta de línea de comandos de Google Cloud. Viene preinstalada en Cloud Shell y es compatible con el completado de línea de comando.

  • Puedes solicitar el nombre de la cuenta activa con este comando:
gcloud auth list

Resultado:

Credentialed accounts: - @.com (active)

Resultado de ejemplo:

Credentialed accounts: - google1623327_student@qwiklabs.net
  • Puedes solicitar el ID del proyecto con este comando:
gcloud config list project

Resultado:

[core] project =

Resultado de ejemplo:

[core] project = qwiklabs-gcp-44776a13dea667a6 Nota: La documentación completa de gcloud está disponible en la guía de descripción general de gcloud CLI .

Tarea 1: crear y probar una aplicación web simple con Flask para Python

En esta tarea, crearás y probarás una aplicación de Python que se usará para almacenar una lista de libros.

Nota: En la mayoría de los lenguajes, se usa sangría para que el código sea más legible. En Python, también se usa para marcar bloques de código, por lo que debe aplicarse correctamente. La cantidad de espacios que se usarán en ella debe ser coherente. Mezclar espacios y tabulaciones en la sangría también puede causar problemas. En este lab, se usan cuatro espacios para la sangría de Python.

Confirma que Cloud Shell esté autorizado

  1. Para confirmar que Cloud Shell esté autorizado, en Cloud Shell, ejecuta el siguiente comando:

    gcloud auth list
  2. Si se te solicita que autorices Cloud Shell, haz clic en Autorizar.

Crea el directorio de apps

Para crear el directorio de apps, ejecuta el siguiente comando:

mkdir ~/bookshelf

Los archivos de la aplicación se crean en el directorio ~/bookshelf.

Especifica y, luego, instala los requisitos

Un archivo de requisitos de Python es un archivo de texto simple en el que se detallan las dependencias que requiere tu proyecto. Para empezar, se necesitan tres módulos en un archivo de requisitos.

Nuestra app está escrita con Flask, un módulo de framework web que facilita el diseño de aplicaciones web con Python. Ejecutamos la aplicación con Gunicorn, un servidor HTTP de Python que se ejecuta en Linux. Por último, Cloud Logging se usa para registrar información desde nuestra aplicación.

  1. Para crear el archivo de requisitos, ejecuta el siguiente comando:

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

    El archivo requirements.txt especifica las versiones de Flask, Gunicorn y Google Cloud Logging que usa la aplicación.

  2. Para instalar las versiones seleccionadas de las dependencias, ejecuta el siguiente comando:

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

    pip es el instalador de paquetes para Python. Este comando pip3 instala los paquetes especificados en el archivo requirements.txt para usarlos con la versión 3 de Python.

Crea la implementación de la base de datos de libros

  1. Para crear el código de la base de datos de libros, ejecuta el siguiente comando:

    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

    Los libros se almacenan en un diccionario de Python, que es una estructura de datos para almacenar pares clave-valor. La clave debe ser única, por lo que la función get_next_id() crea un ID nuevo cada vez que se la llama.

    La función read(book_id) recupera el elemento correspondiente al book_id proporcionado.

    La función create(data) agrega el libro a la base de datos obteniendo un ID nuevo, almacenándolo en los datos del libro y, luego, almacenando la entrada de datos en el diccionario.

    La función update(data, book_id) actualiza el libro en la base de datos guardando el ID proporcionado en los datos del libro y, luego, almacenando la entrada de datos en el diccionario.

    La función delete(book_id) quita la entrada de la base de datos con la clave book_id proporcionada.

    La función list() muestra una lista de Python que contiene cada libro de la base de datos. Para recuperar esta lista, ejecuta un bucle en el diccionario y recupera cada elemento. Cada elemento almacena su ID con la clave id.

Crea los archivos de plantillas HTML

Las plantillas son archivos que contienen datos estáticos y marcadores de posición para datos dinámicos. Renderizarás una plantilla para producir un archivo HTML final.

  1. Para crear la plantilla base, ejecuta el siguiente comando:

    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

    Cada página de la aplicación tiene el mismo diseño básico con un cuerpo diferente. Cada una de las tres plantillas principales (lista, vista y formulario) extiende esta plantilla base especificando el contenido que se mostrará en el centro de la página.

  2. Para crear la plantilla de la lista, ejecuta el siguiente comando:

    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

    La plantilla de lista ejecuta un bucle en lista de libros enviados a la plantilla y muestra el título, el autor y el vínculo de cada libro, que lleva al usuario a la página de visualización de ese libro.

  3. Para crear la plantilla de vista, ejecuta el siguiente comando:

    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

    La plantilla de vista muestra los detalles del libro: título, autor, fecha de publicación y descripción. También proporciona dos botones: uno para editar el libro (que envía al usuario a la plantilla del formulario) y otro para borrar el libro (que borra el libro y devuelve al usuario a la lista de libros).

  4. Para crear la plantilla del formulario, ejecuta el siguiente comando:

    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

    La plantilla del formulario tiene dos propósitos. Cuando se actualiza un libro, la plantilla muestra los detalles del libro actual en cuadros de edición. Cuando se hace clic en el botón Save, los campos del formulario actualizados se guardan en la base de datos.

    Cuando se crea un libro nuevo, los cuadros de detalles del libro están vacíos. Cuando se hace clic en el botón Save, los datos del libro se guardan en la base de datos como un libro nuevo.

Crea el archivo de código principal

  1. Para crear el archivo de código principal, ejecuta el siguiente comando:

    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

    main.py es el punto de entrada de la aplicación. El archivo implementa la aplicación de Flask, que especifica el enrutamiento de la URL web, renderiza las plantillas y administra la base de datos de libros. Si quieres, puedes examinar el código, que está bien comentado.

Prueba la aplicación

  1. Para verificar el contenido del directorio bookshelf, ejecuta el siguiente comando:

    cd ~ ls -R bookshelf

    Deberías ver una lista que contiene dos archivos de Python, un archivo de requisitos y cuatro archivos de plantillas:

    bookshelf: booksdb.py main.py requirements.txt templates bookshelf/templates: base.html form.html list.html view.html
  2. Para ejecutar el servidor HTTP de Gunicorn, ejecuta el siguiente comando:

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

    Si creaste los archivos correctamente, la aplicación debería ahora estar alojada en el puerto 8080.

  3. Para ejecutar la aplicación en el navegador web, haz clic en Vista previa en la Web (Web Preview) y, luego, selecciona Preview on port 8080.

    Vista previa en el puerto 8080

    Se abre una nueva pestaña en el navegador y la aplicación está en ejecución. Esta es la URL raíz, que muestra una lista de todos los libros existentes. Aún no hay libros.

    Nota: Si se te solicita que autorices Cloud Shell, haz clic en Autorizar.
  4. En la pestaña de la aplicación, haz clic en +Agregar libro.

  5. Ingresa un título, autor, fecha y descripción de un libro, real o imaginario, y, luego, haz clic en Guardar.

    Regresarás a la página de visualización y se mostrarán los detalles de tu libro. Puedes editar o borrar tu libro haciendo clic en el botón correspondiente.

  6. En la parte superior de la página, haz clic en Libros.

    Regresarás a la página de visualización y se mostrarán en la lista los libros que hayas agregado.

    Puedes navegar por la aplicación para agregar, editar o borrar libros si lo deseas.

  7. En Cloud Shell, presiona CTRL-C para salir de la aplicación.

Para verificar este objetivo, haz clic en Revisar mi progreso. Crea y prueba una aplicación web simple con Flask para Python.

Tarea 2: usar Firestore para la base de datos de libros

En esta tarea, usarás una base de datos de Firestore para almacenar los datos del libro.

Actualmente, la aplicación usa un diccionario de Python en memoria. Los libros se pierden cuando la app se cierra o falla. Una mejor solución es usar Firestore para la base de datos persistente.

Crea la base de datos de Firestore

  1. En el menú de navegación (Ícono del menú de navegación), navega a Ver todos los productos > Bases de datos.

  2. Haz clic en el ícono de fijar junto a Firestore para agregarlo al menú de navegación y, luego, haz clic en Firestore.

  3. Haz clic en Crear una base de datos de Firestore.

  4. En Opciones de configuración, selecciona Firestore nativo.

  5. En Tipo de ubicación, haz clic en Región.

    No uses una multirregión para Firestore en este lab.

  6. En Región, selecciona y, luego, haz clic en Crear base de datos.

    Nota: Se debe seleccionar la región exacta para la ubicación. Si no ves esta región en la lista desplegable, verifica que hayas seleccionado correctamente Región, no Multirregión, en el Tipo de ubicación.

    Si no hay regiones en la lista desplegable, cancela, vuelve a la página anterior y vuelve a intentar el proceso de creación de la base de datos.

    La creación de la base de datos puede tardar unos minutos. Las colecciones en Firestore se crean automáticamente cuando agregas un documento a una colección, por lo que no necesitas crear una colección de libros ahora mismo.

    La creación de la base de datos de Firestore habilita la API de Firestore.

Modifica la aplicación para que requiera el cliente de Python para Firestore

El cliente de Python para la API de Firestore se usa para acceder a los datos de Firestore desde tus aplicaciones. El nombre del paquete de este cliente es google-cloud-firestore y la versión que se debe usar es 2.12.0.

  1. Modifica la aplicación para que requiera la versión 2.12.0 del paquete google-cloud-firestore.
Nota: Puedes usar cualquier editor de archivos que desees, incluidos nano, vi y el editor de Cloud Code.
  1. Para instalar la dependencia actualizada, ejecuta el siguiente comando:

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

Modifica la aplicación para almacenar datos de libros en Firestore

Ahora que la aplicación requiere el paquete google-cloud-firestore, puedes usarlo en la implementación de la base de datos de libros.

Con Firestore, los datos del libro se almacenan en la base de datos de Firestore. Si tus datos tienen un campo único garantizado que se puede usar como ID, puedes elegir usarlo como ID en Firestore. En este caso, los datos que estás usando no tienen un campo único. Firestore puede crear automáticamente el ID cuando creas un libro nuevo.

Este es un ejemplo de cómo se usa el cliente de 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()

Luego, modifica la implementación de la base de datos de libros para usar Firestore.

Nota: Recuerda que se deben usar cuatro espacios para la sangría de Python.

La implementación actual usa una variable global llamada db, que es un diccionario de Python en memoria. También usa la variable next_id y la función get_next_id(), que crea los IDs de los elementos almacenados en el diccionario.

Firestore administra la creación de IDs por ti. Usa una colección llamada books. Debes agregar el ID creado al diccionario de Python que contiene los detalles de un libro antes de devolverlo al llamador.

Nota: Las pistas ocultan los cambios que debes realizar en el código. Puedes intentar escribir el código por tu cuenta o hacer clic en los botones de pistas para que se agregue el código.
  1. En un editor de archivos, abre el archivo ~/bookshelf/booksdb.py.

  2. Quita las siguientes líneas del archivo:

    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 datos en memoria y la funcionalidad de creación de IDs no son necesarias en esta implementación.

  3. Agrega el código que importa el cliente de Firestore.

  1. Crea una función que convierta un documento de Firestore en un diccionario.

Cuando devuelvas un libro al llamador, no debe ser necesario que el llamador comprenda los documentos de Firestore. Las interfaces de las funciones de la base de datos de libros no deben cambiar, por lo que esta implementación sigue devolviendo y aceptando libros como diccionarios de Python.

El ID del libro debe agregarse al diccionario antes de que se muestre.

Crea una función llamada document_to_dict() que tome un documento de Firestore como parámetro de entrada y devuelva un diccionario. El diccionario incluye los pares clave-valor en el documento y también devuelve el ID del documento como el valor de la clave id. Si el documento no existe, debes mostrar None.

  1. Modifica la función read() para recuperar un libro de la colección de Firestore books. Tu función actualizada debe llamar a la función document_to_dict().
  1. Modifica la función create() para crear un libro en la colección de Firestore books.
  1. Modifica la función update() para actualizar un libro en la colección de Firestore books.
  1. Modifica la función delete() para borrar un libro en la colección de Firestore books.
  1. Modifica la función list() para que devuelva una lista de todos los libros de la colección de Firestore books, ordenados por título.

Listo. Cuando actualizas booksdb.py, modificas la app para que use Firestore como base de datos sin tener que cambiar el código de llamada.

Prueba la aplicación actualizada

  1. En Cloud Shell, ejecuta el siguiente comando:

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

    Si actualizaste los archivos correctamente, la aplicación debería ahora estar alojada en el puerto 8080.

    Nota: Si recibes un error de importación, asegúrate de haber usado pip3 para instalar los requisitos actualizados que ahora incluyen el paquete google.cloud.firestore. Nota: Si se te solicita que autorices Cloud Shell, haz clic en Autorizar.
  2. Para ejecutar la aplicación en el navegador web, haz clic en Vista previa en la Web y, luego, selecciona Preview on port 8080.

    No hay libros en la base de datos porque los libros se almacenaban en un diccionario en memoria.

  3. En la pestaña de la aplicación, haz clic en +Agregar libro.

  4. Ingresa la siguiente información en el formulario:

    Campo Valor
    Title Hamlet
    Author William Shakespeare
    Date Published 1603
    Description A prince contemplates life, death, and revenge, but mostly just makes puns.
  5. Haz clic en Guardar.

    Regresarás a la página de visualización y se mostrarán los detalles de tu libro.

  6. En la parte superior de la página, haz clic en Libros.

    Volverás a la página de la lista y verás Hamlet en ella.

    Nota: Puedes agregar otros libros si quieres, pero no modifiques Hamlet, que es necesario para la siguiente tarea.
  7. En el menú de navegación (Ícono del menú de navegación) de la consola de Google Cloud, haz clic en Firestore.

    Nota: Incluso si ya estás en la página de la consola de Firestore, es posible que debas navegar a la página nuevamente para ver la base de datos.
  8. Haz clic en (predeterminado).

    Deberías ver que se creó un documento en la colección books para Hamlet.

  9. En Cloud Shell, presiona CTRL-C para salir de la aplicación.

Solución de problemas de la tarea 2

Los errores que se encuentran en tu aplicación se imprimen actualmente en Cloud Shell. Si tu aplicación no funciona o no guarda los datos en Firestore, usa la información de error para depurar y solucionar el problema.

Si tienes problemas para que funcione el código de la base de datos de libros, la siguiente pista proporciona un comando para reemplazar el archivo booksdb.py completo por código funcional.

Para verificar este objetivo, haz clic en Revisar mi progreso. Usa Firestore para la base de datos de libros.

Tarea 3: usar Cloud Storage para las portadas de libros

En esta tarea, usarás Cloud Storage para almacenar las imágenes de portada de los libros.

Por lo general, una base de datos no es la ubicación adecuada para almacenar imágenes. No puedes almacenar archivos en Cloud Shell, ya que, en algún momento, querrás alojar la aplicación en otro lugar. Cloud Storage es una solución perfecta para almacenar los recursos que quieres compartir. Cloud Storage es el almacén de objetos principal de Google Cloud.

Crea el bucket de Cloud Storage

Para usar Cloud Storage, debes crear un bucket de Cloud Storage, que es un contenedor básico en el que se guardan tus datos.

  1. En la consola de Google Cloud, en el menú de navegación (Ícono del menú de navegación), haz clic en Cloud Storage > Buckets.

  2. Haz clic en +Crear.

  3. Utiliza este nombre para el bucket:

    {{{ project_0.project_id | project_id }}}-covers
  4. Haz clic en Continuar.

  5. Selecciona la Región.

  6. Selecciona .

  7. Haz clic en Continuar.

  8. No cambies la clase de almacenamiento y haz clic en Continuar.

  9. Desmarca Aplicar la prevención de acceso público a este bucket.

    Dejarás el Control de acceso en Uniforme, que usa permisos a nivel de bucket para todos los objetos que se agregan al bucket.

  10. Haz clic en Crear.

    Para que las portadas sean visibles en la aplicación, debes permitir que todos los usuarios lean objetos dentro del bucket.

  11. Selecciona la pestaña Permisos y, luego, haz clic en Otorgar acceso.

  12. En Principales nuevas, ingresa allUsers.

  13. Para el rol, selecciona Cloud Storage Legacy > Lector de objetos heredados de almacenamiento.

    Nota: El rol Cloud Storage > Visualizador de objetos de Storage incluye el permiso para enumerar objetos en un bucket, que no es necesario para esta aplicación. El rol Cloud Storage Legacy > Lector de objetos heredados de almacenamiento solo permite la recuperación de objetos, lo que es más apropiado para este caso de uso.
  14. Haz clic en Guardar.

  15. Si se te solicita confirmación, haz clic en Permitir acceso público.

Actualiza el archivo de requisitos

  1. En Cloud Shell, en un editor de archivos, abre el archivo ~/bookshelf/requirements.txt.

  2. En el archivo ~/bookshelf/requirements.txt, agrega la siguiente línea:

    google-cloud-storage==2.10.0

    El archivo requirements.txt ahora debería verse de la siguiente manera:

    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. Guarda el archivo.

  4. Para instalar la dependencia actualizada, ejecuta el siguiente comando en Cloud Shell:

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

Crea el código que subirá imágenes a Cloud Storage

El archivo storage.py contiene código para subir una imagen de portada a Cloud Storage.

  1. Para crear el archivo storage.py, ejecuta el siguiente comando:

    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 función upload_file() acepta un flujo de archivo, un nombre de archivo y el tipo de contenido del archivo. Primero, se valida la extensión del nombre de archivo con una lista de extensiones aprobadas que se crea en un paso futuro. Luego, se agrega el nombre de archivo con la fecha y hora actuales para que las imágenes de libros que usan el mismo nombre de archivo cuando se suben no generen conflictos. El resto de la función interactúa con Cloud Storage.

    El nombre del bucket se crea primero con el ID del proyecto:

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

    Luego, se crea una referencia a un objeto para el bucket y el nombre de archivo especificados, y se sube el contenido del archivo de imagen:

    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)

    Luego, los datos del archivo se suben a Cloud Storage y el archivo se hace público para que se pueda mostrar en la aplicación web:

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

    Luego, se devuelve la URL para que se pueda almacenar en la base de datos del libro y se pueda usar para mostrar la imagen.

Modifica las plantillas para mostrar imágenes de libros

Una plantilla se renderiza con datos específicos para producir una página web.

No es necesario cambiar la plantilla base, pero las plantillas de contenido (formulario, lista, vista) deben modificarse para mostrar y subir las portadas de los libros.

  1. En un editor de archivos, abre el archivo ~/bookshelf/templates/form.html.

    El formulario debe modificarse para recopilar el archivo de imagen.

  2. Cerca de la parte inferior del formulario, arriba del control del botón Guardar, agrega las siguientes líneas:

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

    La entrada image permite que el usuario suba un archivo de imagen y también muestra la imagen actual. El input imageUrl está oculto, pero almacena la URL pública de la imagen, que se agrega a la entrada de la base de datos del libro.

    Ahora, el formulario debería verse de la siguiente manera:

    <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. Guarda el archivo.

  4. En un editor de archivos, abre el archivo ~/bookshelf/templates/view.html.

    La imagen del libro debería mostrarse a la izquierda de la información del libro.

  5. Después de la línea <div class="media">, agrega las siguientes líneas:

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

    Con esto, se agrega una nueva sección a la izquierda de los detalles del libro. Si la imagen del libro existe, se muestra en esta sección. De lo contrario, se muestra una imagen de marcador de posición.

    La div media ahora se ve de la siguiente manera:

    <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. Guarda el archivo.

  7. En un editor de archivos, abre el archivo ~/bookshelf/templates/list.html.

    La imagen del libro ahora debería aparecer a la izquierda de cada libro de la lista.

  8. Después de la línea <a href="/books/{{book.id}}">, agrega las siguientes líneas:

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

    Esto contiene el mismo código que agregaste a la plantilla de vista.

Modifica main.py

El archivo de código principal debe subir la imagen a Cloud Storage cuando se publique el formulario, y la URL de la imagen debe agregarse a los datos del libro.

  1. En un editor de archivos, abre ~/bookshelf/main.py.

  2. Después de la importación de booksdb, agrega la siguiente línea:

    import storage
  3. Después de las líneas de importación, agrega el método 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

    Esta función llama a la función de la biblioteca que creaste en storage.py para subir el archivo de portada a Cloud Storage. Devuelve la URL pública del archivo cargado.

  4. Agrega la siguiente línea a la sección app.config.update:

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

    Esto limita las extensiones que se permiten cuando se sube una portada de libro. Ahora, la configuración debería verse de la siguiente manera:

    app.config.update( SECRET_KEY='secret', MAX_CONTENT_LENGTH=8 * 1024 * 1024, ALLOWED_EXTENSIONS=set(['png', 'jpg', 'jpeg', 'gif']), )
  5. En la función add(), después de la línea data = request.form.to_dict(flat=True), agrega el siguiente código:

    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

    Este código llama a la función upload_image_file para subir la imagen que se agregó en el formulario. También agrega la URL de la imagen a los datos del libro.

  6. En la función edit(), después de la línea data = request.form.to_dict(flat=True), agrega el siguiente código:

    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

    Este es el mismo código que agregaste a la función add().

  7. Guarda el archivo.

Prueba la aplicación actualizada

  1. En Cloud Shell, ejecuta el siguiente comando:

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

    Si actualizaste los archivos correctamente, la aplicación debería ahora estar alojada en el puerto 8080.

    Nota: Si se te solicita que autorices Cloud Shell, haz clic en Autorizar.
  2. Para ejecutar la aplicación en el navegador web, haz clic en Vista previa en la Web y, luego, selecciona Preview on port 8080.

    Se deberían mostrar los libros que se agregaron cuando la aplicación usó Firestore. Cada libro muestra la imagen de portada de marcador de posición, ya que las URLs de las imágenes no se agregaron previamente a la base de datos.

  3. Haz clic en Hamlet y, luego, en Edit book.

  4. Haz clic con el botón derecho en la imagen de la portada del libro Hamlet y guárdala en tu computadora como hamlet.png:

    Portada del libro Hamlet

  5. En la app de Bookshelf, en Cover Image, haz clic en Choose File.

  6. Selecciona el archivo que descargaste (hamlet.png) y haz clic en Abrir.

  7. Haz clic en Guardar.

    Ahora debería mostrarse la imagen del libro Hamlet.

  8. En la consola de Google Cloud, en el menú de navegación (Ícono del menú de navegación), haz clic en Cloud Storage > Buckets.

  9. Haz clic en el nombre del bucket (-covers).

    La imagen de portada se guarda en Cloud Storage.

Para verificar este objetivo, haz clic en Revisar mi progreso. Usa Cloud Storage para las portadas de libros.

¡Felicitaciones!

Probaste correctamente una aplicación en Cloud Shell. Modificaste la aplicación para usar las bibliotecas cliente de Cloud y almacenar sus datos en Firestore y las imágenes en Cloud Storage.

Próximos pasos/Más información

Finalice su lab

Cuando haya completado el lab, haga clic en Finalizar lab. Google Cloud Skills Boost quitará los recursos que usó y limpiará la cuenta.

Tendrá la oportunidad de calificar su experiencia en el lab. Seleccione la cantidad de estrellas que corresponda, ingrese un comentario y haga clic en Enviar.

La cantidad de estrellas indica lo siguiente:

  • 1 estrella = Muy insatisfecho
  • 2 estrellas = Insatisfecho
  • 3 estrellas = Neutral
  • 4 estrellas = Satisfecho
  • 5 estrellas = Muy satisfecho

Puede cerrar el cuadro de diálogo si no desea proporcionar comentarios.

Para enviar comentarios, sugerencias o correcciones, use la pestaña Asistencia.

Copyright 2024 Google LLC. Todos los derechos reservados. Google y el logotipo de Google son marcas de Google LLC. El resto de los nombres de productos y empresas pueden ser marcas de las respectivas empresas a las que están asociados.

Anterior
Siguiente

Antes de comenzar

  1. Los labs crean un proyecto de Google Cloud y recursos por un tiempo determinado
  2. .
  3. Los labs tienen un límite de tiempo y no tienen la función de pausa. Si finalizas el lab, deberás reiniciarlo desde el principio.
  4. En la parte superior izquierda de la pantalla, haz clic en Comenzar lab para empezar

Usa la navegación privada

  1. Copia el nombre de usuario y la contraseña proporcionados para el lab
  2. Haz clic en Abrir la consola en modo privado

Accede a la consola

  1. Accede con tus credenciales del lab. Si usas otras credenciales, se generarán errores o se incurrirá en cargos.
  2. Acepta las condiciones y omite la página de recursos de recuperación
  3. No hagas clic en Finalizar lab, a menos que lo hayas terminado o quieras reiniciarlo, ya que se borrará tu trabajo y se quitará el proyecto

Este contenido no está disponible en este momento

Te enviaremos una notificación por correo electrónico cuando esté disponible

¡Genial!

Nos comunicaremos contigo por correo electrónico si está disponible

Un lab a la vez

Confirma para finalizar todos los labs existentes y comenzar este

Usa la navegación privada para ejecutar el lab

Usa una ventana de navegación privada o de Incógnito para ejecutar el lab. Así evitarás cualquier conflicto entre tu cuenta personal y la cuenta de estudiante, lo que podría generar cargos adicionales en tu cuenta personal.
Vista previa