Docs 菜单
Docs 主页
/ /

教程:将 Flask 从SQL迁移到MongoDB

本教程向您展示如何将 Flask应用程序从SQL迁移到MongoDB。具体来说,本教程将使用 SQLAlchemy 的示例博客应用程序转换为使用 Flask- PyMongo 的应用程序。

该示例应用程序包括以下功能:

  • 创建、编辑和查看博客文

  • 搜索博客文

MongoDB是一种将数据存储在文档中的 NoSQL数据库。以下列表描述了MongoDB 的关键概念:

  • 集合:文档群组,类似于SQL数据库中的表。集合不实施执行模式。

  • 文档:用于存储数据的类似JSON 的对象。文档可以包含数组和嵌套子文档。

  • BSON : MongoDB内部使用的二进制JSON格式。 BSON使用日期和二进制等其他数据类型扩展了JSON 。

下表对MongoDB和SQL数据库进行了比较:

功能
SQL
MongoDB

架构

使用预定义的表和列实施固定模式

支持动态数据模型的灵活模式

数据结构

将数据存储在具有行和列的表中

将数据存储在文档集合中

关系

使用外键和联接建立表之间的关系

将文档嵌入其他文档或引用其他文档,无需联接

查询语言

使用结构化查询语言 (SQL)

使用基于JSON 的丰富查询语言

本教程向您展示如何完成以下步骤:

  • 验证先决条件

  • 安装 Flask- PyMongo

  • 更新 Flask应用程序模型

  • 更新 Flask应用程序配置

  • 更新 Flask应用程序路由

  • 从 SQLite 导出数据

  • 将数据导入MongoDB

  • 更新 Flask 模板

  • 运行迁移的应用程序

1

本教程需要满足以下先决条件:

  • MongoDB安装在本地计算机上。有关说明,请参阅MongoDB Server手册中的 安装MongoDB指南。

  • 使用 SQLAlchemy 的现有 Flask应用程序。在本教程中,您可以使用 GitHub 上的flask-mongo存储库中的示例Flask应用程序。

  • Python 3.7 或更高版本。

flask-mongo示例应用程序包含两个子文件夹:flask-mongoflask-sqlflask-sql 文件夹包含一个使用 SQLAlchemy 的 Flask应用程序,您可以将其用于本教程中的迁移。

在开始迁移之前,请完成以下操作:

  1. 查看您的SQL数据库模式,包括表、关系和数据类型。

  2. 识别MongoDB中可能需要特殊处理的复杂查询和关系。

  3. 在设计MongoDB模式,应考虑数据库面向文档的性质。要学习;了解有关MongoDB中模式设计的更多信息,请参阅MongoDB Server手册中的设计模式指南。

  4. 创建当前SQL数据库的完整备份。

2

Flask- PyMongo是一个 Flask 扩展,它将MongoDB与 Flask 应用程序集成在一起。

通过运行以下命令来安装 Flask- PyMongo :

pip install Flask-PyMongo Flask
3

models.py文件的内容替换为以下代码:

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}')"

此代码定义了一个 Post 类,用于对MongoDB 的博文进行建模。该类包括以下方法:

  • __init__:设置每个帖子的标题、内容、发布日期和唯一标识符

  • to_dict:将实例转换为字典以供MongoDB存储

  • from_dict:从字典创建 Post实例

  • __repr__:返回帖子的字符串表示形式

4

__init__.py文件的内容替换为以下代码:

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

此代码将初始化 Flask应用程序,以通过 Flask- PyMongo扩展使用MongoDB 。

通过添加以下代码来更新 config.py文件以包含MongoDB设置:

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

删除 manage.py文件。您可以使用此文件在SQL中进行数据库迁移,这不适应用MongoDB。

注意

如果您需要迁移MongoDB,Beanie ODM 可以提供迁移支持。

5

routes.py文件的内容替换为以下代码:

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)

此代码更新路由以使用MongoDB而不是 SQLAlchemy。这些路由完成以下操作:

  • 使用 to_dict 方法将 Post 实例转换为字典,以便在MongoDB中存储

  • 使用以下方法检索帖子 mongo.db.posts.find()

  • 使用 插入帖子 mongo.db.posts.insert_one()

  • 更新帖子,方法是使用 mongo.db.posts.update_one()

  • 删除帖子,方法是使用 mongo.db.posts.delete_one()

  • 使用 MongoDB 的正则表达式功能搜索帖子

6

通过将以下代码添加到新文件,创建名为 export_list_tables.py 的Python脚本以列出 SQLite数据库中的所有表:

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)

运行此脚本以显示表名称。输出显示了 post 表。

创建另一个名为 export_to_json.py 的Python脚本,通过将以下代码添加到新文件来将数据导出为JSON :

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

运行此脚本以在当前目录中创建 post.json文件。此文件包含JSON格式的导出数据。

7

通过将以下代码添加到新文件中,创建名为 import_to_mongo.py 的Python脚本以将JSON文件导入MongoDB :

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)

运行此脚本以将数据导入MongoDB。该脚本将 date_posted字段转换为日期时间对象,并将所有帖子插入MongoDB集合。

注意

连接字符串mongodb://localhost:27017/blogdb 连接到本地主机上的MongoDB实例的端口 27017。首次写入数据时, MongoDB会自动创建数据库。

8

通过将 post_id=post.id 的所有实例更改为 post_id=post._id,更新模板文件以使用MongoDB文档ID 。

9

通过运行以下命令来运行 Flask应用程序:

python run.py

您可以通过在网络浏览器中导航至 http://127.0.0.1:5000/home访问权限您的应用程序。

要学习;了解有关 Flask-Pymongo 的更多信息,请参阅 Flask- PyMongo文档。

后退

教程:将 Flask 应用部署到Azure容器应用

在此页面上