Connect to MongoDB from Flask-PyMongo

Get started with dockerized MongoDB

Get the MongoDB image from here: https://hub.docker.com/_/mongo. Setup the MongoDB container using docker-compose (docker-compose.yaml):

version: '3.1'

services:
  mongo:
    image: mongo:4.0.8-xenial
    restart: always
    network_mode: bridge
    container_name: mongo
    environment:
      MONGO_INITDB_DATABASE: admin
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
    ports:
      - 27017:27017
    volumes:
      - ./mongodbdata:/data/db
      - ./initdb:/docker-entrypoint-initdb.d

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8081:8081
    network_mode: bridge
    external_links:
      - mongo:mongo
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: root
      ME_CONFIG_MONGODB_ENABLE_ADMIN: 'true'
      ME_CONFIG_MONGODB_SERVER: 'mongo'
    depends_on:
      - mongo

The docker compose file also includes an admin dashboard mongo-express. If you don't need it, you can just get rid of it. I have used two volumes, one is for saving the data on host machine and the other is for initializing MongoDB with default user.

volumes:
  - ./mongodbdata:/data/db # To save data on host machine
  - ./initdb:/docker-entrypoint-initdb.d # Initialize with a default user

The user init script is in the folder initdb. It (init.js) looks like this:

// Authenticate using root user/password
db.auth('root', 'root')

// Provide the database name for your app. 
// Generally you want to create a separate 
// database and user for the app you're 
// building.
db = db.getSiblingDB('new_database_name')

// Now define your user
db.createUser({
    user: 'new_user_name',
    pwd: 'new_user_password',
    roles: [ // Define the roles this new user will have
        {
            role: 'root',
            db: 'admin',
        },
    ],
});

Start the docker container running this following command:

docker-compose -f docker-compose.yaml up

In case you need to start over and rebuild the container, you can use:

docker-compose -f docker-compose.yaml up --force-create --build

Get started with dockerized Flask

I have already written another post explaining how to get started with dockerized Flask. You can read it [here]. After you created your dockerized flask app, the files structure of the project will look something like this:

root_dir
|_ docker-compose.yaml
|_ project_dir
    |_ app_dir
    |_ Dockerfile
    |_ requirements.txt
    |_ run.py

The Dockerfile for this project can be created with the following instructions:

FROM python:3.6

# To avoid invalidating docker's build
# cache everytime we are copying the app
# into the image, we will copy the 
# requirements.txt first and then in later
# step we will copy the entire app
COPY requirements.txt /usr/src/app/
WORKDIR /usr/src/app
RUN pip install -r requirements.txt

COPY . /usr/src/app
CMD ["python", "/usr/src/app/run.py"]

Though I have only one docker container for the flask app, but still I decided to use docker compose because docker compose feels very compact to me when it comes building and running. Here how my docker compose file looks like:

version: '3'

services:
  flaskapp:
    build: ./project_dir
    volumes:
      - ./project_dir:/usr/src/app
    ports:
      - 5080:5080
    network_mode: bridge
    external_links:
      - mongo:mongo
    environment:
      - DEBUG=1
      - DEV=1
      - PROD=0
      - HTTP_GUEST_PORT=5080
      - HTTP_HOST_PORT=5080
      - MONGODB_NAME=flaskapp_dev
      - MONGODB_USER=flaskapp
      - MONGODB_PASSWORD=flaskapp
      - MONGODB_PORT=27017
      - MONGODB_HOST=mongo

Now we are ready to move onto the flask project and integrate the database into our app. We will update our app's __init__.py script this way:

'''
The core module to init an instance of our site app.
'''
import os
from flask import Flask
from .config import app_config
from flask_pymongo import PyMongo

def create_app():
    '''
    create and configure the app
    '''
    app = Flask(__name__, instance_relative_config=True)

    # Get app instance
    if 'FLASK_ENV' in os.environ:
        app.config.from_object(app_config[os.environ['FLASK_ENV']])
    else:
        app.config.from_object(app_config['development'])

    # ensure the instance folder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    # Prepare the database
    app.config['MONGO_URI'] = 'mongodb://{}:{}@{}:{}/{}'.format(
        os.environ['MONGODB_USER'],
        os.environ['MONGODB_PASSWORD'],
        os.environ['MONGODB_HOST'],
        os.environ['MONGODB_PORT'],
        os.environ['MONGODB_NAME'])

    return app

app = create_app()
db = PyMongo(app)

And we are done. Now we can just start the database docker container and then our flask app's container. We will be able to access our flask app at http://localhost:5080. We can also access the mongo-express database admin panel to check our database at http://localhost:8081.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back To Top