对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

教程:将 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-mongo 和 flask-sql。flask-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 datetimefrom 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__:返回帖子的string表示形式

4

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

from flask import Flaskfrom flask_pymongo import PyMongofrom 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, requestfrom app import app, mongofrom bson.objectid import ObjectIdfrom app.models import Postfrom 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 databasedb_path = 'relative/path/to/site.db'conn = sqlite3.connect(db_path)cursor = conn.cursor() # Query to get all table namescursor.execute("SELECT name FROM sqlite_master WHERE \ type='table';")tables = cursor.fetchall() # Close the connectionconn.close() print(tables)

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

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

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

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

7

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

from pymongo import MongoClientimport jsonfrom 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文档。