Overview
このチュートリアルでは、FlaskアプリケーションをSQLからMongoDBに移行する方法を説明します。具体的には、このチュートリアルでは、SQLAlchemy を使用する例のブログアプリケーションを、Flask- PyMongo を使用するものに変換します。
この例アプリケーションには、次の機能が含まれています。
ブログ記事の作成、編集、表示
ブログ記事の検索
MongoDBの理解
MongoDB は、ドキュメントにデータを保存する NoSQLデータベースです。以下のリストでは、 MongoDB の主要な概念を説明しています。
コレクション: SQLデータベースのテーブルに似たドキュメントのグループ。コレクションはスキーマを強制しません。
ドキュメント: データを保存するJSONのようなオブジェクト。ドキュメントには配列やネストされたサブドキュメントを含めることができます。
BSON: MongoDB が内部的に使用するバイナリJSON形式。BSON は、日付やバイナリなどの追加のデータ型でJSONを拡張したものです。
次の表は、 MongoDBデータベースとSQLデータベースを比較したものです。
機能 | SQL | MongoDB |
|---|---|---|
スキーマ | 事前定義されたテーブルと列を含む固定スキーマを強制 | 動的データモデルを可能にする柔軟なスキーマ |
データ構造 | 行と列を含むテーブルにデータを保存 | ドキュメントのコレクションにデータを保存 |
関係 | テーブル間の関係を確立するために外部キーと結合を使用します | ドキュメントを他のドキュメントに埋め込みます。または参照します。結合は必要ありません |
クエリ言語 | 構造化クエリ言語の使用(SQL) | 豊富なJSONベースのクエリ言語を使用 |
Tutorial
このチュートリアルでは、次の手順を実行する方法について説明します。
前提条件を確認します
フラグのインストール- PyMongo
[Flask]アプリケーションモデルを更新します
[Flask]アプリケーション構成を更新します
[Flask]アプリケーションルートを更新します
SQLite からのデータのエクスポート
MongoDBへのデータのインポート
[Flask] テンプレートを更新します
移行したアプリケーションの実行
前提条件を確認します
このチュートリアルには次の前提条件が必要です。
MongoDB はローカルマシンにインストールされています。手順については、 MongoDB Serverマニュアルの「 MongoDB のインストール 」ガイドを参照してください。
SQLAlchemy を使用する既存の Fluskアプリケーション。このチュートリアルでは、GitHub の flask-mongo リポジトリの例フラグアプリケーションを使用できます。
Python 3.7 以降。
flask-mongo例アプリケーションには、flask-mongo と flask-sql の 2 つのサブフォルダが含まれています。flask-sql フォルダーには、このチュートリアルの移行に使用できる SQLAlchemy を使用する Flukアプリケーションが含まれています。
移行を開始 する前に、次のアクションを完了してください。
テーブル、関係、データ型など、SQLデータベーススキーマを検討します。
MongoDBで特別な処理を必要とする複雑なクエリと関係を識別します。
データベースの ドキュメント指向 を考慮してMongoDBスキーマを設計します。MongoDBでのスキーマ設計の詳細については、 MongoDB Serverマニュアルの「スキーマの設計」ガイドを参照してください。
現在のSQLデータベースの完全なバックアップを作成します 。
[Flask]アプリケーションモデルを更新します
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}')"このコードでは、 MongoDBのブログ記事をモデル化する Postクラスを定義します。クラスには、次のメソッドが含まれています。
__init__: 各書き込みのタイトル、内容、書き込み日付、一意の識別子を設定to_dict:インスタンスをMongoDBストレージの辞書に変換from_dict: 辞書からPostインスタンスを作成します__repr__: 書き込みの string 表現を返します
[Flask]アプリケーション構成を更新します
__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を使用するようにします。
次のコードを追加して、MongoDB設定を含むように config.pyファイルを更新します。
import os
class Config: SECRET_KEY = os.urandom(24) MONGO_URI = 'mongodb://localhost:27017/blogdb'manage.pyファイルを削除します。このファイルはSQLのデータベース移行に使用しますが、 MongoDBには適用されません。
注意
MongoDB の移行が必要な場合は、Beanie ODM が移行のサポートを提供します。
[Flask]アプリケーションルートを更新します
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)このコードでは、SQLAlchemy の代わりにMongoDBを使用するようにルートを更新します。ルートは次のアクションを完了します。
MongoDBでのストレージに
to_dictメソッドを使用して、Postインスタンスを辞書に変換する次を使用して書き込みを検索する
mongo.db.posts.find()を使用して書き込みを挿入
mongo.db.posts.insert_one()次を使用して書き込みを更新します
mongo.db.posts.update_one()次を使用して書き込みを削除します
mongo.db.posts.delete_one()MongoDB の正規表現機能を使用して投稿を検索
SQLite からのデータのエクスポート
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 テーブルが表示されます。
データをJSONにエクスポートするには、次のコードを新しいファイルに追加して、export_to_json.py という名前の別のPythonスクリプトを作成します。
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形式のエクスポートされたデータが含まれています。
MongoDBへのデータのインポート
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 は、ポート 27017 にあるローカルホスト上のMongoDBインスタンスに接続します。MongoDB は最初にデータを書き込むと、データベースを自動的に作成します。