Docs Menu
Docs Home
/ /
Third-Party Integrations

Tutorial: Migrate Flask From SQL to MongoDB

This tutorial shows you how to migrate a Flask application from SQL to MongoDB. Specifically, the tutorial converts an example blog application that uses SQLAlchemy to one that uses Flask-PyMongo.

The example application includes the following features:

  • Creating, editing, and viewing blog posts

  • Searching for blog posts

MongoDB is a NoSQL database that stores data in documents. The following list describes key MongoDB concepts:

  • Collections: Groups of documents, similar to tables in SQL databases. Collections don't enforce a schema.

  • Documents: JSON-like objects that store data. Documents can contain arrays and nested subdocuments.

  • BSON: Binary JSON format that MongoDB uses internally. BSON extends JSON with additional data types such as Date and Binary.

The following table compares MongoDB and SQL databases:

Feature
SQL
MongoDB

Schema

Enforces a fixed schema with predefined tables and columns

Flexible schemas that allow for dynamic data models

Data Structure

Stores data in tables with rows and columns

Stores data in collections of documents

Relationships

Uses foreign keys and joins to establish relationships between tables

Embeds documents within other documents or references them, without the need for joins

Query Language

Uses Structured Query Language (SQL)

Uses a rich, JSON-based query language

This tutorial shows you how to complete the following steps:

  • Verify the prerequisites

  • Install Flask-PyMongo

  • Update the Flask application models

  • Update the Flask application configuration

  • Update the Flask application routes

  • Export data from SQLite

  • Import data into MongoDB

  • Update the Flask templates

  • Run the migrated application

1

This tutorial requires the following prerequisites:

  • MongoDB installed on your local machine. See the Install MongoDB guide in the MongoDB Server manual for instructions.

  • An existing Flask application that uses SQLAlchemy. You can use the example Flask application from the flask-mongo repository on GitHub for this tutorial.

  • Python 3.7 or later.

The flask-mongo example application contains two sub-folders, flask-mongo and flask-sql. The flask-sql folder contains a Flask application that uses SQLAlchemy, which you can use for the migration in this tutorial.

Before you begin the migration, complete the following actions:

  1. Review your SQL database schema, including tables, relationships, and data types.

  2. Identify complex queries and relationships that might require special handling in MongoDB.

  3. Design your MongoDB schema considering the document-oriented nature of the database. To learn more about schema design in MongoDB, see the Designing Your Schema guide in the MongoDB Server manual.

  4. Create a complete backup of your current SQL database.

2

Flask-PyMongo is a Flask extension that integrates MongoDB with Flask applications.

Install Flask-PyMongo by running the following command:

pip install Flask-PyMongo Flask
3

Replace the contents of your models.py file with the following code:

from datetime import datetime
from bson.objectid import ObjectId
class Post:
def __init__(self, title, content, date_posted=None,
_id=None):
self.title = title
self.content = content
self.date_posted = date_posted if date_posted \
else datetime.utcnow()
self._id = _id if _id else ObjectId()
def to_dict(self):
return {
"title": self.title,
"content": self.content,
"date_posted": self.date_posted,
"_id": self._id
}
@staticmethod
def from_dict(data):
return Post(
title=data.get('title'),
content=data.get('content'),
date_posted=data.get('date_posted'),
_id=data.get('_id')
)
def __repr__(self):
return f"Post('{self.title}', \
'{self.date_posted}')"

This code defines a Post class that models a blog post for MongoDB. The class includes the following methods:

  • __init__: Sets the title, content, date posted, and unique identifier for each post

  • to_dict: Converts an instance into a dictionary for MongoDB storage

  • from_dict: Creates a Post instance from a dictionary

  • __repr__: Returns a string representation of the post

4

Replace the contents of your __init__.py file with the following code:

from flask import Flask
from flask_pymongo import PyMongo
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
mongo = PyMongo(app)
from app import routes

This code initializes the Flask application to use MongoDB through the Flask-PyMongo extension.

Update your config.py file to include MongoDB settings by adding the following code:

import os
class Config:
SECRET_KEY = os.urandom(24)
MONGO_URI = 'mongodb://localhost:27017/blogdb'

Delete the manage.py file. You use this file for database migrations in SQL, which doesn't apply to MongoDB.

Note

If you need migrations for MongoDB, the Beanie ODM provides migration support.

5

Replace the contents of your routes.py file with the following code:

from flask import render_template, url_for, flash, \
redirect, request
from app import app, mongo
from bson.objectid import ObjectId
from app.models import Post
from app.forms import PostForm
@app.route("/")
@app.route("/home")
def home():
posts_data = mongo.db.posts.find()
posts = [Post.from_dict(post) for post in posts_data]
return render_template("index.html", posts=posts)
@app.route("/post/new", methods=["GET", "POST"])
def new_post():
form = PostForm()
if form.validate_on_submit():
post = Post(title=form.title.data,
content=form.content.data)
mongo.db.posts.insert_one(post.to_dict())
flash("Your post has been created!", "success")
return redirect(url_for("home"))
return render_template("post.html", title="New Post",
form=form)
@app.route("/post/<post_id>")
def post(post_id):
post_data = mongo.db.posts.find_one_or_404(
{"_id": ObjectId(post_id)})
post = Post.from_dict(post_data)
return render_template("detail.html", post=post)
@app.route("/post/<post_id>/edit", methods=["GET", "POST"])
def edit_post(post_id):
post_data = mongo.db.posts.find_one_or_404(
{"_id": ObjectId(post_id)})
post = Post.from_dict(post_data)
form = PostForm()
if form.validate_on_submit():
updated_post = {
"$set": {"title": form.title.data,
"content": form.content.data}
}
mongo.db.posts.update_one(
{"_id": ObjectId(post_id)}, updated_post)
flash("Your post has been updated!", "success")
return redirect(url_for("post", post_id=post_id))
elif request.method == "GET":
form.title.data = post.title
form.content.data = post.content
return render_template("edit_post.html",
title="Edit Post", form=form)
@app.route("/post/<post_id>/delete", methods=["POST"])
def delete_post(post_id):
mongo.db.posts.delete_one({"_id": ObjectId(post_id)})
flash("Your post has been deleted!", "success")
return redirect(url_for("home"))
@app.route("/search", methods=["GET", "POST"])
def search():
query = request.args.get("query")
posts_data = mongo.db.posts.find(
{
"$or": [
{"title": {"$regex": query,
"$options": "i"}},
{"content": {"$regex": query,
"$options": "i"}},
]
}
)
posts = [Post.from_dict(post) for post in posts_data]
return render_template("index.html", posts=posts)

This code updates the routes to use MongoDB instead of SQLAlchemy. The routes complete the following actions:

  • Convert Post instances to dictionaries by using the to_dict method for storage in MongoDB

  • Retrieve posts by using mongo.db.posts.find()

  • Insert posts by using mongo.db.posts.insert_one()

  • Update posts by using mongo.db.posts.update_one()

  • Delete posts by using mongo.db.posts.delete_one()

  • Search posts by using MongoDB's regex capabilities

6

Create a Python script named export_list_tables.py to list all tables in your SQLite database by adding the following code to a new file:

import sqlite3
# Connect to the SQLite database
db_path = 'relative/path/to/site.db'
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Query to get all table names
cursor.execute("SELECT name FROM sqlite_master WHERE \
type='table';")
tables = cursor.fetchall()
# Close the connection
conn.close()
print(tables)

Run this script to display your table names. The output shows the post table.

Create another Python script named export_to_json.py to export the data to JSON by adding the following code to a new file:

import sqlite3
import json
# Connect to the SQLite database
db_path = 'relative/path/to/site.db'
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Export data from the 'post' table
cursor.execute("SELECT * FROM post")
rows = cursor.fetchall()
# Get the column names
column_names = [description[0] for description in \
cursor.description]
# Convert to list of dictionaries
data = [dict(zip(column_names, row)) for row in rows]
# Save to a JSON file
with open('post.json', 'w') as f:
json.dump(data, f, indent=4)
# Close the connection
conn.close()

Run this script to create the post.json file in the current directory. This file contains your exported data in JSON format.

7

Create a Python script named import_to_mongo.py to import the JSON file into MongoDB by adding the following code to a new file:

from pymongo import MongoClient
import json
from datetime import datetime
def import_json_to_mongo(db_name, collection_name,
json_path):
client = MongoClient("mongodb://localhost:27017/")
db = client[db_name]
def convert_date(data):
# Update 'date_posted' field to datetime object
for item in data:
if 'date_posted' in item:
item['date_posted'] = datetime.strptime(
item['date_posted'],
'%Y-%m-%d %H:%M:%S.%f')
return data
with open(json_path, 'r') as f:
data = json.load(f)
data = convert_date(data)
db[collection_name].insert_many(data)
client.close()
if __name__ == "__main__":
db_name = 'blogdb'
collection_name = 'posts'
json_path = 'flask-mongo/post.json'
import_json_to_mongo(db_name, collection_name,
json_path)

Run this script to import your data into MongoDB. The script converts the date_posted field to a datetime object and inserts all posts into the MongoDB collection.

Note

The connection string mongodb://localhost:27017/blogdb connects to your MongoDB instance on localhost at port 27017. MongoDB creates the database automatically when you first write data.

8

Update your template files to use the MongoDB document ID by changing all instances of post_id=post.id to post_id=post._id.

9

Run the Flask application by running the following command:

python run.py

You can access your application by navigating to http://127.0.0.1:5000/home in your web browser.

To learn more about Flask-Pymongo, see the Flask-PyMongo documentation.

Back

Tutorial: Deploy a Flask App to Azure Container Apps

On this page