arrow_back

Desenvolvimento de aplicativos com o Google Cloud: como armazenar dados de aplicativos

Acesse mais de 700 laboratórios e cursos

Desenvolvimento de aplicativos com o Google Cloud: como armazenar dados de aplicativos

Laboratório 1 hora 30 minutos universal_currency_alt 5 créditos show_chart Intermediário
info Este laboratório pode incorporar ferramentas de IA para ajudar no seu aprendizado.
Acesse mais de 700 laboratórios e cursos

Visão geral

As bibliotecas de cliente do Cloud são o método recomendado para chamar as APIs do Google Cloud em aplicativos. Elas usam as convenções e o estilo naturais da linguagem de programação usada no aplicativo. As bibliotecas de cliente do Cloud lidam com a comunicação de baixo nível com o servidor, incluindo a lógica de autenticação e repetição.

O Firestore é um banco de dados de documentos NoSQL rápido, totalmente gerenciado e sem servidor, criado para fins de escalonamento automático, alto desempenho e facilidade de desenvolvimento de aplicativos.

O Cloud Storage é um armazenamento unificado de objetos que permite disponibilizar, analisar e arquivar dados em qualquer lugar do mundo.

Neste laboratório, você vai criar um aplicativo em Python que gerencia uma lista de livros. É possível adicionar, editar e excluir livros, coletando dados como autor, título e descrição. O aplicativo inicial armazena os dados em um dicionário Python na memória, então todos os livros são perdidos quando o aplicativo falha.

Você vai modificar o aplicativo para armazenar todos os dados dos livros no Firestore, além de adicionar o recurso de armazenar uma imagem da capa do livro, que será persistente no Cloud Storage.

O que você vai aprender

Neste laboratório, você vai aprender a:

  • Criar um aplicativo da Web simples com Python Flask.
  • Criar um banco de dados do Firestore para armazenar dados do aplicativo.
  • Criar um bucket do Cloud Storage para armazenar imagens para uso no aplicativo.

Configuração e requisitos

Para cada laboratório, você recebe um novo projeto do Google Cloud e um conjunto de recursos por um determinado período sem custo financeiro.

  1. Clique no botão Começar o laboratório. Se for preciso pagar, você verá um pop-up para selecionar a forma de pagamento. No painel Detalhes do laboratório à esquerda, você vai encontrar o seguinte:

    • O botão Abrir console do Google Cloud
    • O tempo restante
    • As credenciais temporárias que você vai usar neste laboratório
    • Outras informações, se forem necessárias
  2. Se você estiver usando o navegador Chrome, clique em Abrir console do Google Cloud ou clique com o botão direito do mouse e selecione Abrir link em uma janela anônima.

    O laboratório ativa os recursos e depois abre a página Fazer login em outra guia.

    Dica: coloque as guias em janelas separadas lado a lado.

    Observação: se aparecer a caixa de diálogo Escolher uma conta, clique em Usar outra conta.
  3. Se necessário, copie o Nome de usuário abaixo e cole na caixa de diálogo Fazer login.

    {{{user_0.username | "Nome de usuário"}}}

    Você também encontra o Nome de usuário no painel Detalhes do laboratório.

  4. Clique em Seguinte.

  5. Copie a Senha abaixo e cole na caixa de diálogo de boas-vindas.

    {{{user_0.password | "Senha"}}}

    Você também encontra a Senha no painel Detalhes do laboratório.

  6. Clique em Seguinte.

    Importante: você precisa usar as credenciais fornecidas no laboratório, e não as da sua conta do Google Cloud. Observação: se você usar sua própria conta do Google Cloud neste laboratório, é possível que receba cobranças adicionais.
  7. Acesse as próximas páginas:

    • Aceite os Termos e Condições.
    • Não adicione opções de recuperação nem autenticação de dois fatores (porque essa é uma conta temporária).
    • Não se inscreva em testes gratuitos.

Depois de alguns instantes, o console do Google Cloud será aberto nesta guia.

Observação: para acessar uma lista de produtos e serviços do Google Cloud, clique no Menu de navegação no canto superior esquerdo ou digite o nome do serviço ou produto no campo Pesquisar. Ícone do menu de navegação

Ative o Google Cloud Shell

O Google Cloud Shell é uma máquina virtual com ferramentas de desenvolvimento. Ele tem um diretório principal permanente de 5 GB e é executado no Google Cloud.

O Cloud Shell oferece acesso de linha de comando aos recursos do Google Cloud.

  1. No console do Cloud, clique no botão "Abrir o Cloud Shell" na barra de ferramentas superior direita.

    Ícone do Cloud Shell em destaque

  2. Clique em Continuar.

O provisionamento e a conexão do ambiente podem demorar um pouco. Quando você estiver conectado, já estará autenticado, e o projeto estará definido com seu PROJECT_ID. Exemplo:

ID do projeto em destaque no terminal do Cloud Shell

A gcloud é a ferramenta de linha de comando do Google Cloud. Ela vem pré-instalada no Cloud Shell e aceita preenchimento com tabulação.

  • Para listar o nome da conta ativa, use este comando:
gcloud auth list

Saída:

Credentialed accounts: - @.com (active)

Exemplo de saída:

Credentialed accounts: - google1623327_student@qwiklabs.net
  • Para listar o ID do projeto, use este comando:
gcloud config list project

Saída:

[core] project =

Exemplo de saída:

[core] project = qwiklabs-gcp-44776a13dea667a6 Observação: a documentação completa da gcloud está disponível no guia com informações gerais sobre a gcloud CLI .

Tarefa 1: criar e testar um aplicativo da Web simples em Python Flask

Nesta tarefa, você vai criar e testar um aplicativo Python usado para armazenar uma lista de livros.

Observação: na maioria das linguagens, o recuo é usado para tornar o código mais legível. O Python usa o recuo para indicar um bloco de código, então o recuo precisa estar correto. O número de espaços usados no recuo precisa ser consistente. Misturar espaços e tabulações para recuo também pode causar problemas. Este laboratório usa quatro espaços para os recuos do Python.

Verifique se o Cloud Shell tem autorização

  1. Para verificar se o Cloud Shell tem autorização, execute este comando no Cloud Shell:

    gcloud auth list
  2. Se for solicitado que você autorize o Cloud Shell, clique em Autorizar.

Crie o diretório do app

Para criar o diretório do app, execute este comando:

mkdir ~/bookshelf

Os arquivos do aplicativo serão criados no diretório ~/bookshelf.

Especifique e instale os requisitos

O arquivo de requisitos de Python é um arquivo em texto simples que contém as dependências que o projeto exige. Para começar, precisamos incluir três módulos no arquivo.

O app é escrito com o Flask, um módulo de framework da Web que simplifica o design de aplicativos da Web usando o Python. Usamos o Gunicorn, um servidor HTTP do Python que é executado no Linux, para executar o aplicativo. Usamos o Cloud Logging para registrar as informações do aplicativo.

  1. Para criar o arquivo de requisitos, execute este comando:

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

    O arquivo requirements.txt especifica as versões do Flask, do Gunicorn e do Google Cloud Logging usados pelo aplicativo.

  2. Para instalar as versões selecionadas das dependências, execute o seguinte comando:

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

    O utilitário pip é o instalador de pacotes de Python. O comando pip3 instala os pacotes especificados no arquivo requirements.txt para uso com a versão 3 do Python.

Crie a implementação do banco de dados de livros

  1. Para criar o código do banco de dados de livros, execute o seguinte comando:

    cat > ~/bookshelf/booksdb.py <<EOF db = {} # Dicionário Python global na memória. A chave deve sempre ser uma string next_id = 1 # Próximo ID de livro a ser usado def get_next_id(): """ Return the next ID. Incrementa automaticamente ao recuperar um. """ global next_id id = next_id # O próximo ID é 1 mais alto next_id = next_id + 1 # Retorna uma versão do ID em string return str(id) def read(book_id): """ Return the details for a single book. """ # Busca um livro no banco de dados por ID data = db[str(book_id)] return data def create(data): """ Create a new book and return the book details. """ # Gera outro ID para o livro book_id = get_next_id() # Define o ID nos dados do livro data['id'] = book_id # Armazena o livro no banco de dados db[book_id] = data return data def update(data, book_id): """ Update an existing book, and return the updated book's details. """ # O ID do livro deve sempre ser uma string book_id_str = str(book_id) # Adiciona o ID aos dados do livro data['id'] = book_id_str # Atualiza o livro no banco de dados db[book_id_str] = data return data def delete(book_id): """ Delete a book in the database. """ # Remove o livro do banco de dados del db[str(book_id)] # Não é preciso retorno def list(): """ Return a list of all books in the database. """ # Lista de livros vazia books = [] # Busca cada item no banco de dados e o adiciona à lista for k in db: books.append(db[k]) # Retorna a lista return books EOF

    Os livros estão sendo armazenados em uma lista do Python, que é uma estrutura de dados para armazenar pares de chave-valor. A chave precisa ser exclusiva, então a função get_next_id() cria um ID sempre que é chamada.

    A função read(book_id) recupera o item correspondente ao book_id informado.

    A função create(data) adiciona o livro ao banco de dados, obtendo um novo ID, armazenando esse ID nos dados do livro e armazenando a entrada de dados no dicionário.

    A função update(data, book_id) atualiza o livro no banco de dados armazenando o ID informado nos dados do livro e armazenando a entrada de dados no dicionário.

    A função delete(book_id) remove a entrada no banco de dados com a chave book_id informada.

    A função list() retorna uma lista do Python que contém cada livro no banco de dados. Para gerar a lista, ele percorre o dicionário e recupera cada item. Cada item armazena o próprio ID usando a chave id.

Crie os arquivos de modelo HTML

Modelos são arquivos que contêm dados estáticos e marcadores de posição para dados dinâmicos. Você renderiza um modelo para produzir um arquivo HTML final.

  1. Para criar o modelo base, execute o seguinte 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 do aplicativo tem o mesmo layout básico com um corpo diferente. Cada um dos três modelos principais (list, view e form) estende esse modelo básico ao especificar o conteúdo que vai ficar no centro da página.

  2. Para criar o modelo list, execute o seguinte 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

    O modelo list percorre a lista de livros enviados a ele e exibe o título, o autor e o link de cada um. O link leva o usuário à página de visualização do livro.

  3. Para criar o modelo view, execute o seguinte 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

    O modelo view mostra os detalhes do livro: título, autor, data de publicação e descrição. Ele também tem dois botões: um para editar o livro (que abre o modelo form) e outro para exclusão (que exclui o livro e abre de novo a lista).

  4. Para criar o modelo form, execute o seguinte 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

    O modelo form tem duas finalidades. Durante a atualização de um livro, o modelo mostra os detalhes atuais em caixas editáveis. Quando o usuário clica no botão Save, os campos do formulário atualizados são salvos no banco de dados.

    Quando um livro é criado, as caixas de detalhes estão vazias. Quando o usuário clica no botão Save, os dados do livro são salvos no banco de dados como um novo livro.

Crie o arquivo de código principal

  1. Para criar o arquivo de código principal, execute o seguinte 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) # Gera a lista de livros books = booksdb.list() # Renderiza a lista de livros 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) # Busca determinado livro book = booksdb.read(book_id) # Renderiza os detalhes do livro 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) # Salva os detalhes se o formulário foi publicado if request.method == 'POST': # Busca os dados do livro no formulário data = request.form.to_dict(flat=True) # Adiciona o livro book = booksdb.create(data) # Renderiza os dados do livro return redirect(url_for('.view', book_id=book['id'])) # Renderiza o formulário para adicionar o livro 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) # Lê os dados do livro book = booksdb.read(book_id) # Salva os dados se o formulário foi publicado if request.method == 'POST': # Busca os dados do livro no formulário data = request.form.to_dict(flat=True) # Atualiza o livro book = booksdb.update(data, book_id) # Renderiza os dados do livro return redirect(url_for('.view', book_id=book['id'])) # Renderiza o formulário de atualização do livro 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) # Exclui o livro booksdb.delete(book_id) # Renderiza a lista dos livros restantes return redirect(url_for('.list')) # Usado apenas na execução local if __name__ == '__main__': app.run(host='127.0.0.1', port=8080, debug=True) EOF

    main.py é o ponto de entrada do aplicativo. O arquivo implementa o aplicativo Flask, que especifica o roteamento de URL da Web, renderiza os modelos e gerencia o banco de dados de livros. Confira o código, que está bem comentado.

Teste o aplicativo

  1. Para verificar o conteúdo do diretório bookshelf, execute o seguinte comando:

    cd ~ ls -R bookshelf

    Uma lista com dois arquivos Python, um arquivo de requisitos e quatro arquivos de modelo vão aparecer:

    bookshelf: booksdb.py main.py requirements.txt templates bookshelf/templates: base.html form.html list.html view.html
  2. Para executar o servidor HTTP Gunicorn, execute o seguinte comando:

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

    Se você criou os arquivos corretamente, o aplicativo vai estar hospedado na porta 8080.

  3. Para executar o aplicativo no navegador da Web, clique em Visualização da Web e selecione Visualizar na porta 8080.

    Visualizar na porta 8080

    Uma nova guia é aberta no navegador, e o aplicativo é executado. Esse é o URL raiz, que mostra uma lista de todos os livros. Ainda não há livros.

    Observação: se for preciso autorizar o Cloud Shell, clique em Autorizar.
  4. Na guia do aplicativo, clique em +Add book.

  5. Digite o título, o autor, a data e a descrição de um livro, real ou imaginário, e clique em Save.

    A página de visualização será aberta com os detalhes do livro. Clique no botão correspondente para editar ou excluir o livro.

  6. Na parte superior da página, clique em Books.

    A página de visualização será aberta de novo, e os livros adicionados vão aparecer na lista.

    Você pode navegar pelo aplicativo para adicionar, editar ou excluir livros.

  7. No Cloud Shell, para sair do aplicativo, pressione CTRL+C.

Para verificar o objetivo, clique em Verificar meu progresso. Criar e testar um aplicativo da Web simples em Python Flask

Tarefa 2: usar o Firestore para o banco de dados de livros

Nesta tarefa, você vai usar um banco de dados do Firestore para armazenar os dados dos livros.

Atualmente, o aplicativo usa um dicionário Python na memória. Os livros são perdidos sempre que o app é encerrado ou falha. Uma solução melhor é usar o Firestore como banco de dados permanente.

Crie o banco de dados do Firestore

  1. No menu de navegação (Ícone do menu de navegação), acesse Mostrar todos os produtos > Bancos de dados.

  2. Clique no ícone Fixar ao lado de Firestore para adicionar esse item ao menu de navegação, depois clique em Firestore.

  3. Clique em Criar um banco de dados do Firestore.

  4. Em Opções de configuração, selecione Nativa do Firestore.

  5. Em Tipo de local, clique em Região.

    Não use Multirregional para o Firestore neste laboratório.

  6. Em Região, selecione e clique em Criar banco de dados.

    Observação: selecione exatamente a região como local. Se você não encontrar essa região na lista suspensa, verifique se selecionou Região, e não Multirregional, em Tipo de local.

    Se não houver regiões na lista suspensa, cancele, volte para a página anterior e crie o banco de dados de novo.

    A criação do banco de dados pode levar alguns minutos. As coleções no Firestore são criadas automaticamente quando você adiciona um documento a uma coleção. Por isso, não é necessário criar uma coleção de livros agora.

    A criação do banco de dados do Firestore ativa a API Firestore.

Modifique o aplicativo para exigir o cliente Python do Firestore

O cliente Python da API Firestore é usado para acessar os dados do Firestore em aplicativos. O nome do pacote do cliente é google-cloud-firestore, e a versão a ser usada é 2.12.0.

  1. Modifique o aplicativo para exigir a versão 2.12.0 do pacote google-cloud-firestore.
Observação: use qualquer editor de arquivos, como nano, vi e o editor de código do Cloud.
  1. Para instalar a dependência atualizada, execute o seguinte comando:

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

Modifique o aplicativo para armazenar dados de livros no Firestore

Agora que o aplicativo exige o pacote google-cloud-firestore, você pode usá-lo na implementação do banco de dados de livros.

Com o Firestore, os dados de livros são armazenados no banco de dados do Firestore. Quando os dados contêm um campo que certamente é exclusivo, é possível usá-lo como ID no Firestore. Neste caso, os dados que você está usando não têm um campo exclusivo. O Firestore pode criar o ID automaticamente quando você cria um livro.

Confira um exemplo de como o cliente do Firestore é usado:

from google.cloud import firestore # Busca o cliente db = firestore.Client() # Cria um documento data = {"name": "Sue", "role": "treasurer"} member_ref = db.collection("members").document() member_ref.set(data) member_id = member_ref.get().id # Recupera um documento 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.") # Atualiza um documento new_data = {"name": "Sue", "role": "president"} member_ref = db.Collection("members").document(member_id) member_ref.set(new_data) # Coloca os documentos na ordem members = db.collection("members").order_by("name").stream() for member in members: print(f"{member.id} => {member.to_dict()}") # Exclui um membro member_ref = db.Collection("members").document(member_id) member_ref.delete()

Em seguida, você vai modificar a implementação do banco de dados de livros para usar o Firestore.

Observação: lembre-se de usar quatro espaços para o recuo do Python.

A implementação atual usa uma variável global chamada db, que é um dicionário Python na memória. Ele também usa a variável next_id e a função get_next_id(), que cria os IDs dos itens armazenados no dicionário.

O Firestore gerencia a criação de IDs. Use uma coleção chamada livros. É necessário adicionar o ID criado ao dicionário Python que contém os detalhes de um livro antes de retornar o livro ao autor da chamada.

Observação: as dicas ocultam as alterações de código que você precisa fazer. Tente escrever o código por conta própria, ou clique nos botões de dica para mostrar o código a ser adicionado.
  1. Em um editor de arquivos, abra o arquivo ~/bookshelf/booksdb.py.

  2. Remova as seguintes linhas do arquivo:

    db = {} # Dicionário global Python na memória. A chave deve sempre ser uma string next_id = 1 # Próximo ID de livro a ser usado def get_next_id(): """ Return the next ID. Incrementa automaticamente ao recuperar um. """ global next_id id = next_id # O próximo ID é esse valor mais 1 next_id = next_id + 1 # Retorna uma versão do ID em string return str(id)

    O banco de dados na memória e a funcionalidade de criação de IDs não são necessários nesta implementação.

  3. Adicione código que importe o cliente do Firestore.

  1. Crie uma função que converte um documento do Firestore em um dicionário.

É melhor que os autores da chamada não precisem entender documentos Firestore para receber os livros. As interfaces das funções do banco de dados de livros não devem mudar, então essa implementação continua retornando e aceitando livros como dicionários do Python.

O ID do livro precisa ser adicionado ao dicionário antes do retorno.

Crie uma função chamada document_to_dict(), que recebe um documento do Firestore como parâmetro de entrada e retorna um dicionário. O dicionário inclui os pares de chave-valor no documento e também retorna o ID do documento como o valor da chave id. Se o documento não existir, retorne None.

  1. Modifique a função read() para recuperar um livro da coleção books do Firestore. A função atualizada precisa chamar a função document_to_dict().
  1. Modifique a função create() para criar um livro na coleção do Firestore books.
  1. Modifique a função update() para atualizar um livro na coleção books do Firestore.
  1. Modifique a função delete() para excluir um livro na coleção books do Firestore.
  1. Modifique a função list() para retornar uma lista de todos os livros da coleção books do Firestore, ordenados por título.

Pronto! Ao atualizar booksdb.py, você modifica o app para usar o Firestore como banco de dados sem ter que alterar o código de chamada.

Teste o aplicativo atualizado

  1. No Cloud Shell, execute este comando:

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

    Se você atualizou os arquivos corretamente, o aplicativo vai estar hospedado na porta 8080.

    Observação: se aparecer um erro de importação, verifique se você usou o pip3 para instalar os requisitos atualizados, que agora incluem o pacote google.cloud.firestore. Observação: se for necessário autorizar o Cloud Shell, clique em Autorizar.
  2. Para executar o aplicativo no navegador da Web, clique em Visualização da Web e selecione Visualizar na porta 8080.

    Não há livros no banco de dados porque eles estavam sendo armazenados em um dicionário na memória.

  3. Na guia do aplicativo, clique em +Add book.

  4. Digite as seguintes informações no formulário:

    Campo Valor
    Title Hamlet
    Author William Shakespeare
    Date Published 1603
    Description A prince contemplates life, death, and revenge, but mostly just makes puns.
  5. Clique em Save.

    A página de visualização será aberta com os detalhes do livro.

  6. Na parte superior da página, clique em Books.

    A página da lista será aberta de novo, e Hamlet vai aparecer na lista.

    Observação: é possível adicionar outros livros, mas não modifique o Hamlet, que será necessário para a próxima tarefa.
  7. No console do Google Cloud, acesse o menu de navegação (Ícone do menu de navegação) e clique em Firestore.

    Observação: mesmo que você já esteja na página do console do Firestore, talvez seja necessário acessá-la de novo para ver o banco de dados.
  8. Clique em (padrão).

    Um documento referente a Hamlet foi criado na coleção books.

  9. No Cloud Shell, para sair do aplicativo, pressione CTRL+C.

Tarefa de solução de problemas 2

Os erros encontrados no aplicativo são mostrados no Cloud Shell. Se o aplicativo não estiver funcionando ou salvando os dados no Firestore, use as informações de erro para depurar e corrigir o problema.

Se você tiver problemas para fazer o código do banco de dados de livros funcionar, use o comando na dica a seguir para substituir todo o arquivo booksdb.py por um código que funciona.

Para verificar o objetivo, clique em Verificar meu progresso. Usar o Firestore para o banco de dados de livros

Tarefa 3: usar o Cloud Storage para capas de livros

Nesta tarefa, você vai usar o Cloud Storage para armazenar imagens das capas dos livros.

Um banco de dados geralmente não é o local certo para armazenar imagens. Não é possível armazenar arquivos no Cloud Shell, porque você vai hospedar o aplicativo em outro lugar no futuro. O Cloud Storage é a solução perfeita para armazenar recursos que você quer compartilhar. O Cloud Storage é o principal repositório de objetos do Google Cloud.

Crie o bucket do Cloud Storage

Para usar o Cloud Storage, você precisa criar um bucket, um contêiner básico para guardar os dados.

  1. No console do Google Cloud, acesse o Menu de navegação (Ícone do menu de navegação) e clique em Cloud Storage > Buckets.

  2. Clique em +Criar.

  3. Para nomear o bucket, use:

    {{{ project_0.project_id | project_id }}}-covers
  4. Clique em Continuar.

  5. Selecione Região.

  6. Selecione .

  7. Clique em Continuar.

  8. Deixe a classe de armazenamento inalterada e clique em Continuar.

  9. Remova Aplicar a prevenção do acesso público neste bucket.

    Deixe a opção Controle de acesso como Uniforme, que usa permissões de nível de bucket para todos os objetos adicionados ao bucket.

  10. Clique em Criar.

    Para que as capas sejam exibidas no aplicativo, todos os usuários precisam ter permissão para ler os objetos no bucket.

  11. Selecione a guia Permissões e clique em Conceder acesso.

  12. Em Novos principais, digite allUsers.

  13. Para o papel, selecione Legado do Cloud Storage > Leitor de objeto legado do Storage.

    Observação: o papel Cloud Storage > Leitor de objetos do Storage inclui a permissão para conferir os objetos em um bucket, o que não é necessário neste aplicativo. O papel Legado do Cloud Storage > Leitor de objeto legado do Storage só permite a recuperação de objetos, o que é mais adequado para este caso de uso.
  14. Clique em Salvar.

  15. Se for preciso confirmar, clique em Permitir acesso público.

Atualize o arquivo de requisitos

  1. No Cloud Shell, em um editor de arquivos, abra o arquivo ~/bookshelf/requirements.txt.

  2. No arquivo ~/bookshelf/requirements.txt, adicione a seguinte linha:

    google-cloud-storage==2.10.0

    O arquivo requirements.txt deve ficar assim:

    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. Salve o arquivo.

  4. Para instalar a dependência atualizada, no Cloud Shell, execute o seguinte comando:

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

Crie um código que faz upload de imagens para o Cloud Storage

O arquivo storage.py contém o código para fazer upload de uma imagem de capa para o Cloud Storage.

  1. Para criar o arquivo storage.py, execute o seguinte 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) # Cria o nome do bucket bucket_name = os.getenv('GOOGLE_CLOUD_PROJECT') + '-covers' client = storage.Client() # Cria um objeto de bucket bucket = client.bucket(bucket_name) # Cria um objeto no bucket para o caminho especificado blob = bucket.blob(filename) # Faz upload do conteúdo da string no objeto blob.upload_from_string( file_stream, content_type=content_type) # Obtém o URL público do objeto, usado para armazenar uma referência # à imagem no banco de dados e mostrar a imagem no 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

    A função upload_file() aceita um fluxo de arquivo, um nome de arquivo e o tipo de conteúdo do arquivo. O app verifica se a extensão do nome do arquivo está na lista de extensões aprovadas, que será criada em uma etapa futura. Depois ele adiciona a data e a hora atuais ao nome do arquivo, para evitar conflitos entre imagens de livros com o mesmo nome. O restante da função interage com o Cloud Storage.

    O nome do bucket é criado primeiro usando o ID do projeto:

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

    Depois o app cria uma referência ao objeto do bucket especificado e o nome do arquivo, além de fazer o upload do arquivo de imagem:

    client = storage.Client() # Cria um objeto de bucket bucket = client.bucket(bucket_name) # Cria um objeto no bucket para o caminho especificado blob = bucket.blob(filename)

    Os dados do arquivo são enviados para o Cloud Storage, e o arquivo é tornado público para poder ser exibido no app da Web:

    # Faz upload do conteúdo da string no objeto blob.upload_from_string( file_stream, content_type=content_type)

    O URL é retornado para ser armazenado no banco de dados do livro e usado para mostrar a imagem.

Modifique os modelos para exibir as imagens de livros

Um modelo é renderizado com dados específicos para produzir uma página da Web.

O modelo base não precisa ser alterado, mas os modelos de conteúdo (form, list, view) precisam ser alterados para exibir e fazer upload das capas dos livros.

  1. Em um editor de arquivos, abra o arquivo ~/bookshelf/templates/form.html.

    O formulário precisa ser modificado para coletar o arquivo de imagem.

  2. Próximo à parte de baixo do formulário, acima do controle do botão Save, adicione as linhas a seguir:

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

    A entrada image permite que o usuário faça upload de um arquivo de imagem e também exibe a imagem atual. A entrada imageUrl está oculta, mas armazena o URL público da imagem, que é adicionada à entrada do banco de dados do livro.

    O formulário deve ficar assim:

    <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. Salve o arquivo.

  4. Em um editor de arquivos, abra o arquivo ~/bookshelf/templates/view.html.

    A imagem do livro deve ser exibida à esquerda das informações do livro.

  5. Depois da linha <div class="media">, adicione as seguintes linhas:

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

    Uma nova seção será adicionada à esquerda dos detalhes do livro. Se a imagem do livro existir, ela será exibida nessa seção. Caso contrário, ela vai mostrar uma imagem padrão.

    O div media agora ficou assim:

    <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. Salve o arquivo.

  7. Em um editor de arquivos, abra o arquivo ~/bookshelf/templates/list.html.

    A imagem agora vai aparecer à esquerda de cada livro na lista.

  8. Depois da linha <a href="/books/{{book.id}}">, adicione as seguintes linhas:

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

    Esse é o mesmo código que você adicionou ao modelo de view.

Modifique main.py

O arquivo de código principal deve fazer o upload da imagem para o Cloud Storage quando o formulário for postado, e o URL da imagem deve ser adicionado aos dados do livro.

  1. Em um editor de arquivos, abra ~/bookshelf/main.py.

  2. Depois da importação de booksdb, adicione a seguinte linha:

    import storage
  3. Depois das linhas de importação, adicione o 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

    Essa função chama a função da biblioteca que você criou em storage.py para fazer o upload do arquivo de capa para o Cloud Storage. Ela retorna o URL público do arquivo enviado.

  4. Adicione a seguinte linha à seção app.config.update:

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

    Isso limita as extensões permitidas ao fazer o upload de uma capa de livro. A configuração deve ficar assim:

    app.config.update( SECRET_KEY='secret', MAX_CONTENT_LENGTH=8 * 1024 * 1024, ALLOWED_EXTENSIONS=set(['png', 'jpg', 'jpeg', 'gif']), )
  5. Na função add(), depois da linha data = request.form.to_dict(flat=True), adicione o seguinte código:

    image_url = upload_image_file(request.files.get('image')) # Se uma imagem foi enviada, atualiza os dados para apontar para ela. if image_url: data['imageUrl'] = image_url

    Esse código chama a função upload_image_file para fazer upload da imagem que foi adicionada ao formulário. Ele também adiciona o URL da imagem aos dados do livro.

  6. Na função edit(), depois da linha data = request.form.to_dict(flat=True), adicione o seguinte código:

    image_url = upload_image_file(request.files.get('image')) # Se uma imagem foi enviada, atualiza os dados para apontar para ela. if image_url: data['imageUrl'] = image_url

    Esse é o mesmo código que você adicionou à função add().

  7. Salve o arquivo.

Teste o aplicativo atualizado

  1. No Cloud Shell, execute este comando:

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

    Se você atualizou os arquivos corretamente, o aplicativo vai estar hospedado na porta 8080.

    Observação: se for preciso autorizar o Cloud Shell, clique em Autorizar.
  2. Para executar o aplicativo no navegador da Web, clique em Visualização da Web e selecione Visualizar na porta 8080.

    Os livros que foram adicionados quando o aplicativo usou o Firestore devem aparecer. Cada livro mostra a imagem de capa padrão porque os URLs das imagens não foram adicionados ao banco de dados.

  3. Clique em Hamlet e depois em Edit book.

  4. Clique com o botão direito do mouse na imagem da capa do livro Hamlet e salve-a no seu computador como hamlet.png:

    Capa do livro Hamlet

  5. No app Bookshelf, em Cover Image, clique em Choose File.

  6. Selecione o arquivo que você baixou (hamlet.png) e clique em Open.

  7. Clique em Save.

    A imagem do livro Hamlet vai aparecer.

  8. No console do Google Cloud, acesse o Menu de navegação (Ícone do menu de navegação) e clique em Cloud Storage > Buckets.

  9. Clique no nome do bucket (-covers).

    A imagem de capa é salva no Cloud Storage.

Para verificar o objetivo, clique em Verificar meu progresso. Usar o Cloud Storage para capas de livros

Parabéns!

Você testou um aplicativo no Cloud Shell. Você modificou o aplicativo para armazenar dados no Firestore e imagens no Cloud Storage usando as bibliotecas de cliente do Cloud.

Próximas etapas/Saiba mais

Finalize o laboratório

Clique em Terminar o laboratório após a conclusão. O Google Cloud Ensina remove os recursos usados e limpa a conta por você.

Você vai poder avaliar sua experiência no laboratório. Basta selecionar o número de estrelas, digitar um comentário e clicar em Enviar.

O número de estrelas indica o seguinte:

  • 1 estrela = muito insatisfeito
  • 2 estrelas = insatisfeito
  • 3 estrelas = neutro
  • 4 estrelas = satisfeito
  • 5 estrelas = muito satisfeito

Feche a caixa de diálogo se não quiser enviar feedback.

Para enviar seu feedback, fazer sugestões ou correções, use a guia Suporte.

Copyright 2024 Google LLC. Todos os direitos reservados. Google e o logotipo do Google são marcas registradas da Google LLC. Todos os outros nomes de empresas e produtos podem ser marcas registradas das empresas a que estão associados.

Antes de começar

  1. Os laboratórios criam um projeto e recursos do Google Cloud por um período fixo
  2. Os laboratórios têm um limite de tempo e não têm o recurso de pausa. Se você encerrar o laboratório, vai precisar recomeçar do início.
  3. No canto superior esquerdo da tela, clique em Começar o laboratório

Usar a navegação anônima

  1. Copie o nome de usuário e a senha fornecidos para o laboratório
  2. Clique em Abrir console no modo anônimo

Fazer login no console

  1. Faça login usando suas credenciais do laboratório. Usar outras credenciais pode causar erros ou gerar cobranças.
  2. Aceite os termos e pule a página de recursos de recuperação
  3. Não clique em Terminar o laboratório a menos que você tenha concluído ou queira recomeçar, porque isso vai apagar seu trabalho e remover o projeto

Este conteúdo não está disponível no momento

Você vai receber uma notificação por e-mail quando ele estiver disponível

Ótimo!

Vamos entrar em contato por e-mail se ele ficar disponível

Um laboratório por vez

Confirme para encerrar todos os laboratórios atuais e iniciar este

Use a navegação anônima para executar o laboratório

Para executar este laboratório, use o modo de navegação anônima ou uma janela anônima do navegador. Isso evita conflitos entre sua conta pessoal e a conta de estudante, o que poderia causar cobranças extras na sua conta pessoal.