
Before you begin
- Labs create a Google Cloud project and resources for a fixed time
- Labs have a time limit and no pause feature. If you end the lab, you'll have to restart from the beginning.
- On the top left of your screen, click Start lab to begin
Create and test a simple Python Flask web application
/ 30
Use Firestore for the books database
/ 30
Use Cloud Storage for book covers
/ 40
Cloud Client Libraries are the recommended method for calling Google Cloud APIs from your applications. Cloud Client Libraries use the natural conventions and style of the programming language that you're using for your application. Cloud Client Libraries handle low-level communication with the server, including authentication and retry logic.
Firestore is a fast, fully managed, serverless, NoSQL document database built for automatic scaling, high performance, and ease of application development.
Cloud Storage is a unified object storage that lets you serve, analyze, and archive data anywhere in the world.
In this lab, you create a Python application that manages a list of books. You're able to add, edit, and delete books, collecting data like author, title, and description. The initial application stores the data in an in-memory Python dictionary, which causes all books to be lost when the application crashes.
You modify this application to store all the book data in Firestore, and then add the ability to store a cover image for a book, which you persist in Cloud Storage.
In this lab, you learn to:
For each lab, you get a new Google Cloud project and set of resources for a fixed time at no cost.
Click the Start Lab button. If you need to pay for the lab, a pop-up opens for you to select your payment method. On the left is the Lab Details panel with the following:
Click Open Google Cloud console (or right-click and select Open Link in Incognito Window if you are running the Chrome browser).
The lab spins up resources, and then opens another tab that shows the Sign in page.
Tip: Arrange the tabs in separate windows, side-by-side.
If necessary, copy the Username below and paste it into the Sign in dialog.
You can also find the Username in the Lab Details panel.
Click Next.
Copy the Password below and paste it into the Welcome dialog.
You can also find the Password in the Lab Details panel.
Click Next.
Click through the subsequent pages:
After a few moments, the Google Cloud console opens in this tab.
Google Cloud Shell is a virtual machine that is loaded with development tools. It offers a persistent 5GB home directory and runs on the Google Cloud.
Google Cloud Shell provides command-line access to your Google Cloud resources.
In Cloud console, on the top right toolbar, click the Open Cloud Shell button.
Click Continue.
It takes a few moments to provision and connect to the environment. When you are connected, you are already authenticated, and the project is set to your PROJECT_ID. For example:
gcloud is the command-line tool for Google Cloud. It comes pre-installed on Cloud Shell and supports tab-completion.
Output:
Example output:
Output:
Example output:
In this task, you create and test a Python application used to store a list of books.
To confirm that Cloud Shell is authorized, in Cloud Shell, run the following command:
If you're asked to authorize Cloud Shell, click Authorize.
To create the app directory, run the following command:
The application files are created in the ~/bookshelf
directory.
A Python requirements file is a simple text file that lists the dependencies required by your project. To start, there are three modules we need in our requirements file.
Our app is written with Flask, a web framework module that makes it simple to design web applications by using Python. We run the application by using Gunicorn, a Python HTTP server that runs on Linux. Finally, Cloud Logging is used to log information from our application.
To create the requirements file, run the following command:
The requirements.txt file specifies the versions of Flask, Gunicorn, and the Google Cloud logger that are used by the application.
To install the selected versions of the dependencies, run the following command:
pip is the package installer for Python. This pip3
command installs the packages specified in the requirements.txt file for use with Python version 3.
To create the books database code, run the following command:
Books are being stored in a Python dictionary, which is a data structure for storing key-value pairs. The key must be unique, so the get_next_id()
function creates a new ID each time it's called.
The read(book_id)
function retrieves the item corresponding to the provided book_id.
The create(data)
function adds the book to the database by getting a new ID, storing that ID in the data for the book, and then storing the data entry in the dictionary.
The update(data, book_id)
function updates the book in the database by storing the provided ID in the data for the book, and then storing the data entry in the dictionary.
The delete(book_id)
function removes the entry in the database with the provided book_id key.
The list()
function returns a Python list that contains each book in the database. It retrieves this list by looping through the dictionary and retrieving each item. Each item stores its ID by using the id
key.
Templates are files that contain both static data and placeholders for dynamic data. You render a template to produce a final HTML file.
To create the base template, run the following command:
Each page in the application has the same basic layout with a different body. Each of the three main templates (list, view, form) extends this base template by specifying the content to go in the center of the page.
To create the list template, run the following command:
The list template loops through the list of books sent to the template and displays the title, author, and link for each book, with the link that takes the user to the view page for that book.
To create the view template, run the following command:
The view template shows the book details: the title, author, date published, and description. It also provides two buttons: one to edit the book (sending the user to the form template), and one to delete the book (which deletes the book and sends the user back to the book list).
To create the form template, run the following command:
The form template serves two purposes. When updating a book, the template displays the current book details in editable boxes. When the Save button is clicked, the updated form fields are saved into the database.
When creating a new book, the book details boxes start empty. When the Save button is clicked, the book data is saved into the database as a new book.
To create the main code file, run the following command:
main.py is the entry point for the application. The file implements the Flask application, which specifies the web URL routing, renders the templates, and manages the book database. Feel free to examine the code, which is well commented.
To check the contents of the bookshelf directory, run the following command:
You should see a list that contains two Python files, a requirements file, and four template files:
To run the Gunicorn HTTP server, run the following command:
If you have successfully created the files, the application should now be hosted on port 8080.
To run the application in the web browser, click Web Preview, and then select Preview on port 8080.
A new tab is opened in the browser, and the application is running. This is the root URL, which displays a list of all existing books. There are no books yet.
In the application tab, click +Add book.
Enter a title, author, date, and description for a book, real or imaginary, and then click Save.
You're returned to the view page, and your book details are shown. You can edit or delete your book by clicking the appropriate button.
At the top of the page, click Books.
You're returned to the view page, and any books you have added are shown in the list.
You can navigate the application to add, edit, or delete books if you want.
In Cloud Shell, to quit the application, enter CTRL-C
.
To verify the objective, click Check my progress.
In this task, you use a Firestore database to store the book data.
The application currently uses an in-memory Python dictionary. The books are lost whenever the app exits or crashes. A better solution is to use Firestore for the persistent database.
From Navigation menu (), navigate to View All Products > Databases.
Click the Pin icon next to Firestore to add it to the navigation menu, then click Firestore.
Click Create a Firestore Database.
In Configuration options, select Firestore Native.
For Location type, click Region.
You should not use a Multi-Region for Firestore in this lab.
For Region, select
Creating the database might take a few minutes. Collections in Firestore are automatically created when you add a document to a collection, so you don't need to create a book collection right now.
Creating the Firestore database causes the Firestore API to be enabled.
The Python client for the Firestore API is used to access Firestore data from your applications. This client's package name is google-cloud-firestore, and the version to use is 2.12.0.
To install the updated dependency, run the following command:
Now that the application requires the google-cloud-firestore package, you can use it in the books database implementation.
With Firestore, the book data is stored in the Firestore database. If your data had a guaranteed unique field that could be used as an ID, you might choose to use that as the ID in Firestore. In this case, the data you're using doesn't have a unique field. Firestore can automatically create the ID for you when you create a new book.
Here's an example of how the Firestore client is used:
Next, you modify the books database implementation to use Firestore.
The current implementation uses a global variable named db
, which is an in-memory Python dictionary. It also uses the variable next_id
and the function get_next_id()
, which creates the IDs for items stored in the dictionary.
Firestore manages the creation of IDs for you. Use a collection named books
. You must add the created ID to the Python dictionary that contains the details of a book before you return it to the caller.
In a file editor, open the file ~/bookshelf/booksdb.py
.
Remove the following lines from the file:
The in-memory database and ID creation functionality are not needed in this implementation.
Add code that imports the Firestore client.
When you return a book to the caller, you don't want the caller to have to understand Firestore documents. The interfaces for the books database functions should remain unchanged, so this implementation continues to return and accept books as Python dictionaries.
The ID for the book must be added to the dictionary before it's returned.
Create a function named document_to_dict()
which takes a Firestore document as the input parameter and returns a dictionary. The dictionary includes the key-value pairs in the document, and also returns the document ID as the value for the key id
. If the document does not exist, you should return None
.
read()
function to retrieve a book from the Firestore collection books
. Your updated function should call the function document_to_dict()
.create()
function to create a book in the Firestore collection books
.update()
function to update a book in the Firestore collection books
.delete()
function to delete a book in the Firestore collection books
.list()
function to return a list of all books from the Firestore collection books
, sorted by title.That's it! By updating booksdb.py
, you modify the app to use Firestore as the database without having to change the calling code.
In Cloud Shell, run the following command:
If you have successfully updated the files, the application should now be hosted on port 8080.
To run the application in the web browser, click Web Preview, and then select Preview on port 8080.
There are no books in the database because books were being stored into an in-memory dictionary.
In the application tab, click +Add book.
Enter the following information into the form:
Field | Value |
---|---|
Title | Hamlet |
Author | William Shakespeare |
Date Published | 1603 |
Description | A prince contemplates life, death, and revenge, but mostly just makes puns. |
Click Save.
You're returned to the view page, and your book details are shown.
At the top of the page, click Books.
You're returned to the list page, and Hamlet is shown in the list.
In the Google Cloud console, in the Navigation menu (), click Firestore.
Click (default).
You should see that a document has been created in the books collection for Hamlet.
In Cloud Shell, to quit the application, enter CTRL-C
.
Errors that are encountered in your application are currently printed in Cloud Shell. If your application is not working or saving the data to Firestore, use the error information to debug and fix the issue.
If you are having problems getting the books database code to work, the command in the following hint provides a command to replace the entire booksdb.py file with working code.
To verify the objective, click Check my progress.
In this task, you use Cloud Storage to store cover images for the books.
A database is typically not the right location to store images. You can't store files in Cloud Shell, because you would want to eventually host the application somewhere else. Cloud Storage is a perfect solution for storing assets that you want to share. Cloud Storage is the primary object store for Google Cloud.
To use Cloud Storage, you need to create a Cloud Storage bucket, which is a basic container to hold your data.
In the Google Cloud console, in the Navigation menu (), click Cloud Storage > Buckets.
Click +Create.
For the bucket name, use:
Click Continue.
Select Region.
Select
Click Continue.
Leave the storage class unchanged, and click Continue.
Clear Enforce public access prevention on this bucket.
You're leaving the Access Control as Uniform, which uses bucket-level permissions for all objects added to the bucket.
Click Create.
To allow the covers to be visible in the application, you must allow all users to read objects within the bucket.
Select the Permissions tab and then click Grant Access.
For New principals, enter allUsers.
For role, select Cloud Storage Legacy > Storage Legacy Object Reader.
Click Save.
If you're asked for confirmation, click Allow Public Access.
In Cloud Shell, in a file editor, open the file ~/bookshelf/requirements.txt
.
In the ~/bookshelf/requirements.txt
file, add the following line:
The requirements.txt file should now look like this:
Save the file.
To install the updated dependency, in Cloud Shell, run the following command:
The storage.py
file contains code to upload a cover image to Cloud Storage.
To create the storage.py
file, run the following command:
The upload_file()
function accepts a file stream, a filename, and the content type of the file. The filename's extension is first validated against an approved list of extensions that is created in a future step. The filename is then appended with the current date and time, so that book images that use the same filename when uploading won't conflict. The rest of the function interacts with Cloud Storage.
The bucket name is first built by using the project ID:
Next, a reference to an object for the specified bucket and filename is created, and the contents of the image file are uploaded:
The file data is then uploaded to Cloud Storage, and the file is made public so that it can be displayed in the web app:
The URL is then returned so that it can be stored in the book database and used to display the image.
A template is rendered with specific data to produce a web page.
The base template doesn't need to be changed, but the content templates (form, list, view) must be changed to display and upload the book covers.
In a file editor, open the file ~/bookshelf/templates/form.html
.
The form should be modified to collect the image file.
Near the bottom of the form, above the Save button control, add the following lines:
The image input allows the user to upload an image file, and also displays the current image. The imageUrl input is hidden, but it stores the public URL of the image, which is added to the database entry for the book.
The form should now look like this:
Save the file.
In a file editor, open the file ~/bookshelf/templates/view.html
.
The book image should be displayed to the left of the book information.
After the line <div class="media">
, add the following lines:
This adds a new section to the left of the book details. If the book image exists, it displays that image in this section. Otherwise, it displays a placeholder image.
The media
div now looks like this:
Save the file.
In a file editor, open the file ~/bookshelf/templates/list.html
.
The book image should now be displayed to the left of each book in the list.
After the line <a href="/books/{{book.id}}">
, add the following lines:
This contains the same code that you added to the view template.
The main code file should upload the image to Cloud Storage when the form is posted, and the image URL should be added to the book data.
In a file editor, open the file ~/bookshelf/main.py
.
After the import for booksdb
, add the following line:
After the import lines, add the upload_image_file()
method:
This function calls the library function you created in storage.py
to upload the cover file to Cloud Storage. It returns the public URL for the uploaded file.
Add the following line to the app.config.update
section:
This limits the extensions that are allowed when uploading a book cover. The configuration should now look like this:
In the add()
function, after the data = request.form.to_dict(flat=True)
line, add the following code:
This code calls the upload_image_file function to upload the image that was added in the form. It also adds the image URL to the book data.
In the edit()
function, after the data = request.form.to_dict(flat=True)
line, add the following code:
This is the same code you added to the add()
function.
Save the file.
In Cloud Shell, run the following command:
If you have successfully updated the files, the application should now be hosted on port 8080.
To run the application in the web browser, click Web Preview, and then select Preview on port 8080.
The books that were added when the application used Firestore should be displayed. Each book shows the placeholder cover image, because image URLs were not previously added to the database.
Click Hamlet, and then click Edit book.
Right-click this Hamlet book cover image, and save it to your computer as hamlet.png:
In the Bookshelf app, for Cover Image, click Choose File.
Select the file that you downloaded (hamlet.png), and click Open.
Click Save.
The book image for Hamlet should now be displayed.
In the Google Cloud console, in the Navigation menu (), click Cloud Storage > Buckets.
Click the bucket name (
The cover image is saved to Cloud Storage.
To verify the objective, click Check my progress.
You successfully tested an application in Cloud Shell. You modified the application to use Cloud Client Libraries to store its data in Firestore and to store images in Cloud Storage.
When you have completed your lab, click End Lab. Google Cloud Skills Boost removes the resources you’ve used and cleans the account for you.
You will be given an opportunity to rate the lab experience. Select the applicable number of stars, type a comment, and then click Submit.
The number of stars indicates the following:
You can close the dialog box if you don't want to provide feedback.
For feedback, suggestions, or corrections, please use the Support tab.
Copyright 2024 Google LLC All rights reserved. Google and the Google logo are trademarks of Google LLC. All other company and product names may be trademarks of the respective companies with which they are associated.
This content is not currently available
We will notify you via email when it becomes available
Great!
We will contact you via email if it becomes available
One lab at a time
Confirm to end all existing labs and start this one