Using MongoDB with Python

This part of the Bookshelf tutorial shows how the sample app stores its persistent data in a MongoDB database.

This page is part of a multi-page tutorial. To start from the beginning and see instructions for setting up, go to Python Bookshelf App.

Running MongoDB on Google Compute Engine

If you haven't set up a Mongo instance, you can create a managed one running on top of Google Cloud Platform using mLab. If you'd rather use an unmanaged MongoDB instance running on Compute Engine, check out Bitnami's preconfigured click-to-deploy solution.

For best performance, make sure your MongoDB instance is hosted on Google Cloud Platform and located in the same region as your app.

Configuring settings

This section uses code in the 2-structured-data directory. Edit the files and run commands in this directory.

  1. Open config.py for editing.
  2. Set the value of PROJECT_ID to your project ID, which is visible in the GCP Console.
  3. Set the value of DATA_BACKEND to mongodb.
  4. Set the value of PROJECT_ID to your project ID, which is visible in the Google Cloud Platform Console.
  5. Set the value of MONGO_URI. If you’re using mLab, the URI is available from the control panel. If you deployed your own MongoDB cluster as described previously, set the URI to the external IP noted in that section. You can also find the external IP address by running gcloud compute instances list.
  6. Save and close config.py.

Installing dependencies

Enter these commands to create a virtual environment and install dependencies:

Linux/Mac OS X

virtualenv -p python3 env
source env/bin/activate
pip install -r requirements.txt

Windows

virtualenv -p python3 env
env\scripts\activate
pip install -r requirements.txt

Running the app on your local machine:

  1. Start a local web server:

    python main.py
    
  2. In your web browser, enter this address:

    http://localhost:8080

Now you can browse the app's web pages and add, edit, and delete books.

Press Control+C to exit the local web server.

Deploying the app to the App Engine flexible environment

  1. Deploy the sample app:

    gcloud app deploy
    
  2. In your web browser, enter this address. Replace [YOUR_PROJECT_ID] with your project ID:

    https://[YOUR_PROJECT_ID].appspot.com
    

If you update your app, you can deploy the updated version by entering the same command you used to deploy the app the first time. The new deployment creates a new version of your app and promotes it to the default version. The older versions of your app remain, as do their associated VM instances. Be aware that all of these app versions and VM instances are billable resources.

You can reduce costs by deleting the non-default versions of your app.

To delete an app version:

  1. In the Cloud Platform Console, go to the App Engine Versions page.

    Go to the Versions page

  2. Click the checkbox next to the non-default app version you want to delete.
  3. Click the Delete button at the top of the page to delete the app version.

For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.

Application structure

This diagram shows the how the sample application components are connected to each other. The application stores all persistent data in MongoDB.

Bookshelf app deployment process and structure

Understanding the code

This section walks you through the application code and explains how it works.

Handling user submissions with forms

The add/edit HTML form allows users to add and edit book submissions within the app.

Image of add/edit Form

The HTML form is created using Flask's default template engine, Jinja2. The following template defines a simple form that includes input fields for Title, Author, Date Published, and Description:

{% 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 %}

Handling form submissions

When a user clicks Add Book, the crud.add view displays the form. When the user fills out the Add book form and clicks Save, the same view handles the form's HTTP POST action. This initiates the process of sending the submitted data to MongoDB by passing the data to the get_model().create function.

@crud.route('/add', methods=['GET', 'POST'])
def add():
    if request.method == 'POST':
        data = request.form.to_dict(flat=True)

        book = get_model().create(data)

        return redirect(url_for('.view', id=book['id']))

    return render_template("form.html", action="Add", book={})

The bookshelf/model_mongodb.py file contains the code that performs CRUD functions for data stored in MongoDB. For example, the get_model().create statement calls the create function in bookshelf/model_mongodb.py, which sends the user's submitted data to the create function. Here is the create function that does the actual work of saving the user's submitted data to MongoDB.

def create(data):
    new_id = mongo.db.books.insert(data)
    return read(new_id)

When the user edits a book, the update function is used instead.

def update(data, id):
    mongo.db.books.update({'_id': _id(id)}, data)
    return read(id)

The create and update functions both use read, which is also used when the user views a single book.

def read(id):
    result = mongo.db.books.find_one(_id(id))
    return from_mongo(result)

The from_mongo helper function is used to translate a MongoDB document's _id to an id that can be used by the application.

def from_mongo(data):
    """
    Translates the MongoDB dictionary format into the format that's expected
    by the application.
    """
    if not data:
        return None

    data['id'] = str(data['_id'])
    return data

After users have added books, clicking the Books link navigates to the /books page, which list all the books currently stored in MongoDB. The model_mongodb.list function does the work of listing all the books using data retrieved from MongoDB.

def list(limit=10, cursor=None):
    cursor = int(cursor) if cursor else 0

    results = mongo.db.books.find(skip=cursor, limit=10).sort('title')
    books = builtin_list(map(from_mongo, results))

    next_page = cursor + limit if len(books) == limit else None
    return (books, next_page)

This code queries MongoDB using mongo.db.books.find and gets all of the documents in the book collection and returns them ordered by title. The code get results one page at a time and return a cursor to allow the user to load the next page of results.

Send feedback about...