FlaskアプリケーションでMongoDBを使用する方法
著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。
序章
Webアプリケーションでは、通常、データの組織化されたコレクションであるデータベースが必要です。 データベースを使用して、効率的に取得および操作できる永続データを保存および維持します。 たとえば、ソーシャルメディアアプリケーションでは、ユーザーデータ(個人情報、投稿、コメント、フォロワー)が効率的に操作できる方法で保存されているデータベースがあります。 さまざまな要件や条件に応じて、データベースにデータを追加、取得、変更、または削除できます。 Webアプリケーションでは、これらの要件は、ユーザーが新しい投稿を追加したり、投稿を削除したり、アカウントを削除したりする場合があります。これにより、投稿が削除される場合と削除されない場合があります。 データを操作するために実行するアクションは、アプリケーションの特定の機能によって異なります。 たとえば、タイトルのない投稿をユーザーに追加させたくない場合があります。
Flaskは、Python言語でWebアプリケーションを作成するための便利なツールと機能を提供する軽量のPythonWebフレームワークです。 MongoDB は、 JSON のようなドキュメントを使用してデータを格納する、汎用のドキュメント指向のNoSQLデータベースプログラムです。 リレーショナルデータベースで使用される表形式のリレーションとは異なり、JSONのようなドキュメントでは、シンプルさを維持しながら柔軟で動的なスキーマを使用できます。 一般に、NoSQLデータベースは水平方向に拡張できるため、ビッグデータやリアルタイムアプリケーションに適しています。
このチュートリアルでは、PythonでMongoDBデータベースと対話できるようにするMongoDBデータベースドライバーであるPyMongoライブラリの使用方法を示す小さなtodoリストWebアプリケーションを作成します。 これをFlaskで使用して、データベースサーバーへの接続、MongoDBにドキュメントのグループを格納するコレクションの作成、コレクションへのデータの挿入、コレクションからのデータの取得と削除などの基本的なタスクを実行します。
前提条件
- ローカルのPython3プログラミング環境については、 Python3シリーズのローカルプログラミング環境をインストールしてセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリを
flask_appと呼びます。 - ローカルマシンにインストールされたMongoDB。 Ubuntu 20.04にMongoDBをインストールする方法ガイドに従って、MongoDBデータベースをセットアップします。
- ルート、ビュー関数、テンプレートなどの基本的なFlaskの概念の理解。 Flaskに慣れていない場合は、FlaskとPythonを使用して最初のWebアプリケーションを作成する方法およびFlaskアプリケーションでテンプレートを使用する方法を確認してください。
- 基本的なHTMLの概念の理解。 背景知識については、HTMLを使用してWebサイトを構築する方法チュートリアルシリーズを確認できます。
ステップ1—PyMongoとFlaskを設定する
このステップでは、FlaskとPyMongoライブラリをインストールします。
仮想環境をアクティブにした状態で、pipを使用してFlaskとPyMongoをインストールします。
pip install Flask pymongo
インストールが正常に完了すると、出力の最後に次のような行が表示されます。
Output Successfully installed Flask-2.0.2 Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1 pymongo-4.0.1
必要なPythonパッケージをインストールしたので、MongoDBサーバーに接続してコレクションを作成します。
ステップ2—MongoDBサーバーに接続してコレクションを作成する
このステップでは、PyMongoライブラリを使用して、MongoDBサーバーとの対話に使用するクライアントを作成し、データベースを作成してから、タスクを保存するためのコレクションを作成します。
プログラミング環境をアクティブにして、flask_appディレクトリ内で編集するためにapp.pyというファイルを開きます。
nano app.py
このファイルは、FlaskとPyMongoライブラリから必要なクラスとヘルパーをインポートします。 MongoDBサーバーと対話して、データベースを作成し、todoのコレクションを作成します。 次のコードをapp.pyに追加します。
フラスコ_app/app.py
from flask import Flask
from pymongo import MongoClient
app = Flask(__name__)
client = MongoClient('localhost', 27017)
db = client.flask_db
todos = db.todos
ファイルを保存して閉じます。
ここでは、Flaskクラスをインポートします。このクラスを使用して、appというFlaskアプリケーションインスタンスを作成します。
MongoClientをインポートします。これを使用して、clientというMongoDBインスタンスのクライアントオブジェクトを作成します。これにより、MongoDBサーバーに接続して対話できます。 MongoClient()をインスタンス化するときは、MongoDBサーバーのホスト(この場合はlocalhost)と、ここでは27017のポートを渡します。
ノート:
Ubuntu 20.04でMongoDBを保護する方法のガイドに従って、MongoDBインストールのセキュリティを強化することを強くお勧めします。 保護されたら、リモート接続を受け入れるようにMongoDBを構成できます。
MongoDBで認証を有効にしたら、次のようにMongoClient()のインスタンスを作成するときに、追加のusernameおよびpasswordパラメーターを渡す必要があります。
client = MongoClient('localhost', 27017, username='username', password='password')
次に、clientインスタンスを使用して、flask_dbというMongoDBデータベースを作成し、その参照をdbという変数に保存します。
次に、db変数を使用して、flask_dbデータベースにtodosというコレクションを作成します。 コレクションは、リレーショナルデータベースのテーブルのように、ドキュメントのグループをMongoDBに格納します。
MongoDBでは、データベースとコレクションは遅延して作成されます。 つまり、app.pyファイルを実行しても、最初のドキュメントが作成されるまで、データベースに関連するコードは実際には実行されません。 次のステップで、ユーザーがToDoドキュメントをtodosコレクションに挿入できるページを備えた小さなFlaskアプリケーションを作成します。 最初のtodoドキュメントが追加されると、flask_dbデータベースとtodosコレクションがMongoDBサーバーに作成されます。
現在のデータベースのリストを取得するには、新しいターミナルを開き、次のコマンドを使用してmongoシェルを起動します。
mongo
プロンプトが開きます。次のコマンドを使用してデータベースを確認できます。
show dbs
これがMongoDBの新規インストールである場合、出力には、admin、config、およびlocalデータベースがリストされます。
flask_dbがまだ存在していないことに気付くでしょう。 mongoシェルをターミナルウィンドウで実行したままにして、次の手順に進みます。
ステップ3—Todoを追加および表示するためのWebページを作成する
このステップでは、ユーザーがToDoを追加して同じページに表示できるWebフォームを使用してWebページを作成します。
プログラミング環境をアクティブにして、app.pyファイルを開いて編集します。
nano app.py
まず、flaskから次のインポートを追加します。
フラスコ_app/app.py
from flask import Flask, render_template, request, url_for, redirect from pymongo import MongoClient # ...
ここでは、HTMLテンプレートのレンダリングに使用するrender_template()ヘルパー関数、ユーザーが送信するデータにアクセスするためのrequestオブジェクト、URLを生成するためのurl_for()関数をインポートします。 、およびredirect()関数を使用して、todoを追加した後にユーザーをインデックスページにリダイレクトします。
次に、ファイルの最後に次のルートを追加します。
フラスコ_app/app.py
# ...
@app.route('/', methods=('GET', 'POST'))
def index():
return render_template('index.html')
ファイルを保存して閉じます。
このルートでは、タプル('GET', 'POST')をmethodsパラメーターに渡して、GET要求とPOST要求の両方を許可します。 GETリクエストは、サーバーからデータを取得するために使用されます。 POSTリクエストは、特定のルートにデータを投稿するために使用されます。 デフォルトでは、GETリクエストのみが許可されます。 ユーザーが最初にGETリクエストを使用して/ルートをリクエストすると、index.htmlというテンプレートファイルがレンダリングされます。 後でこのルートを編集して、ユーザーが新しいToDoを作成するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。
次に、flask_appディレクトリにテンプレートフォルダを作成し、前のルートで参照したindex.htmlテンプレートを作成します。
mkdir templates nano templates/index.html
index.htmlファイル内に次のコードを追加します。
フラスコ_app/templates / index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FlaskApp</title>
<style>
.todo {
padding: 20px;
margin: 10px;
background-color: #eee;
}
</style>
</head>
<body>
<h1>FlaskTODO</h1>
<hr>
<div class="content">
<form method="post">
<p>
<b><label for="content">Todo content</label></b>
</p>
<p>
<input type="text" name="content"
placeholder="Todo Content"></input>
</p>
<p>
<b><label for="degree">Degree</label></b>
</p>
<p>
<input id="degree-0" name="degree" required type="radio" value="Important">
<label for="degree-0">Important</label>
</p>
<p>
<input id="degree-1" name="degree" required type="radio" value="Unimportant">
<label for="degree-1">Unimportant</label>
</p>
<button type="submit">Submit</button>
</form>
</div>
</body>
</html>
ファイルを保存して閉じます。
ここに、タイトル、いくつかのスタイル、見出し、およびWebフォームを含む基本的なHTMLページがあります。 Webフォームで、method属性をpostに設定して、フォームがPOST要求を送信することを示します。 contentという名前のtodoコンテンツのテキスト入力フィールドがあり、これを使用して/ルートのタイトルデータにアクセスします。 また、degreeという名前の2つのHTMLラジオボタンがあり、ユーザーは各ToDoアイテムの重要度を指定できます。重要オプションまたはのいずれかを選択できます。 ToDoを作成するときの重要でないオプション。 最後に、フォームの最後に送信ボタンがあります。
仮想環境をアクティブにしてflask_appディレクトリにいるときに、FLASK_APP環境変数を使用して、アプリケーション(この場合はapp.py)についてFlaskに通知します。 次に、FLASK_ENV環境変数をdevelopmentに設定して、アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します。
export FLASK_APP=app export FLASK_ENV=development
次に、アプリケーションを実行します。
flask run
注:アプリケーションを実行しようとすると、ModuleNotFoundError: No module named 'pymongo'エラーが発生する場合があります。 これを修正するには、仮想環境を非アクティブ化してから再アクティブ化します。 その後、flask runコマンドを再度実行してください。
開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。
http://127.0.0.1:5000/
ToDoコンテンツの入力フィールド、重要度の2つのラジオボタン、および送信ボタンのあるインデックスページが表示されます。
Webフォームの詳細については、FlaskアプリケーションでWebフォームを使用する方法を参照してください。 Webフォームを管理するためのより高度で安全な方法については、Flask-WTFを使用してWebフォームを使用および検証する方法を参照してください。
フォームに入力して送信し、サーバーにPOSTリクエストを送信しても、/ルートでPOSTリクエストを処理しなかったため、何も起こりません。
サーバーを実行したままにして、新しいターミナルウィンドウを開きます。
app.pyを開いて、ユーザーが送信したPOSTリクエストを処理し、それらをtodosコレクションに追加して、インデックスページに表示します。
nano app.py
/ルートを編集して、次のようにします。
フラスコ_app/app.py
@app.route('/', methods=('GET', 'POST'))
def index():
if request.method=='POST':
content = request.form['content']
degree = request.form['degree']
todos.insert_one({'content': content, 'degree': degree})
return redirect(url_for('index'))
all_todos = todos.find()
return render_template('index.html', todos=all_todos)
ファイルを保存して閉じます。
これらの変更では、if request.method == 'POST'条件内でPOST要求を処理します。 request.formオブジェクトからユーザーが送信するtodoコンテンツと重要度を抽出します。
todosコレクションでinsert_one()メソッドを使用して、todoドキュメントを追加します。 Pythonディクショナリでtodoデータを提供し、'content'をユーザーがtodoコンテンツのテキストフィールドに送信した値に設定し、'degree'キーをラジオボタンの値に設定します。ユーザーが選択します。 次に、インデックスページにリダイレクトします。これにより、ページが更新され、新しく追加されたToDoアイテムが表示されます。
保存されているすべてのToDoを表示するには、POSTリクエストの処理を担当するコードの外部で find()メソッドを使用します。これにより、todosコレクションで使用可能なすべてのTodoドキュメントが返されます。 データベースから取得したtodoをall_todosという変数に保存し、render_template()関数呼び出しを編集して、todoドキュメントのリストをindex.htmlテンプレートに渡します。これは、todosという変数のテンプレートで使用できます。
インデックスページを更新すると、ブラウザからフォームの再送信の確認を求めるメッセージが表示される場合があります。 同意すると、POSTリクエストを処理する前に以前に送信したToDoアイテムがデータベースに追加されます。これは、フォームを処理するためのコードがルートに存在するためです。
インデックスページにはまだToDoアイテムを表示するコードがないため、追加したアイテムは表示されません。 ブラウザにフォームの再送信を許可した場合は、mongoシェルを開き、次のコマンドを使用してflask_dbデータベースに接続することで、新しく追加されたデータを表示できます。
use flask_db
次に、find()関数を使用して、データベース内のすべてのToDoアイテムを取得します。
db.todos.find()
データが再送信された場合は、ここの出力に表示されます。
次に、index.htmlテンプレートを開いて、渡したtodosリストの内容を表示します。
nano templates/index.html
フォームの後に<hr>ブレークとJinjafor loop を追加してファイルを編集し、ファイルが次のようになるようにします。
フラスコ_app/templates / index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FlaskApp</title>
<style>
.todo {
padding: 20px;
margin: 10px;
background-color: #eee;
}
</style>
</head>
<body>
<h1>FlaskTODO</h1>
<hr>
<div class="content">
<form method="post">
<p>
<b><label for="content">Todo content</label></b>
</p>
<p>
<input type="text" name="content"
placeholder="Todo Content"></input>
</p>
<p>
<b><label for="degree">Degree</label></b>
</p>
<p>
<input id="degree-0" name="degree" required type="radio" value="Important">
<label for="degree-0">Important</label>
</p>
<p>
<input id="degree-1" name="degree" required type="radio" value="Unimportant">
<label for="degree-1">Unimportant</label>
</p>
<button type="submit">Submit</button>
</form>
<hr>
{% for todo in todos %}
<div class="todo">
<p>{{ todo['content'] }} <i>({{ todo['degree']}})</i></p>
</div>
{% endfor %}
</div>
</body>
</html>
ファイルを保存して閉じます。
このファイルでは、<hr>タグを追加して、WebフォームとToDoのリストを分離します。
{% for todo in todos %}行のforループを使用して、todosリストの各todo項目を調べます。 <p>タグ内に、todoの内容と重要度を表示します。
次に、インデックスページを更新し、Webフォームに入力して、送信します。 フォームの下に追加したToDoが表示されます。 次に、ユーザーが既存のToDoを削除できるようにするボタンを追加します。
ステップ4—Todoを削除する
このステップでは、ユーザーがボタンを使用してToDoを削除できるルートを追加します。
まず、POSTリクエストを受け入れる新しい/id/deleteルートを追加します。 新しいdelete()ビュー関数は、URLから削除するToDoのIDを受け取り、そのIDを使用して削除します。
ToDoを削除するには、そのIDを文字列として取得し、コレクションのdeleteメソッドに渡す前にObjectIdに変換する必要があります。 したがって、ObjectId()クラスをbsonモジュールからインポートする必要があります。このモジュールはBSON(バイナリJSON)のエンコードとデコードを処理します。
app.pyを開いて編集します。
nano app.py
まず、ファイルの先頭に次のインポートを追加します。
フラスコ_app/app.py
from bson.objectid import ObjectId # ...
これは、文字列IDをObjectIdオブジェクトに変換するために使用するObjectId()クラスです。
次に、最後に次のルートを追加します。
フラスコ_app/app.py
# ...
@app.post('/<id>/delete/')
def delete(id):
todos.delete_one({"_id": ObjectId(id)})
return redirect(url_for('index'))
ファイルを保存して閉じます。
ここでは、通常のapp.routeデコレータを使用する代わりに、Flaskバージョン2.0.0で導入されたapp.post デコレータを使用します。これにより、一般的なHTTPメソッドのショートカットが追加されました。 たとえば、@app.post("/login")は@app.route("/login", methods=["POST"])のショートカットです。 つまり、このビュー関数はPOSTリクエストのみを受け入れ、ブラウザで/ID/deleteルートに移動すると、405 Method Not Allowedエラーが返されます。これは、WebブラウザのデフォルトがGETリクエストであるためです。 ToDoを削除するには、ユーザーはこのルートにPOSTリクエストを送信するボタンをクリックします。
この関数は、削除するToDoドキュメントのIDを受け取ります。 このIDをtodosコレクションのdelete_one()メソッドに渡し、前にインポートしたObjectId()クラスを使用して、受け取った文字列IDをObjectIdに変換します。
ToDoドキュメントを削除した後、ユーザーをインデックスページにリダイレクトします。
次に、index.htmlテンプレートを編集して、Todoの削除ボタンを追加します。
nano templates/index.html
新しい<form>タグを追加して、forループを編集します。
フラスコ_app/templates / index.html
{% for todo in todos %}
<div class="todo">
<p>{{ todo['content'] }} <i>({{ todo['degree']}})</i></p>
<form method="POST" action="{{ url_for('delete', id=todo['_id']) }}" >
<input type="submit" value="Delete Todo"
onclick="return confirm('Are you sure you want to delete this entry?')">
</form>
</div>
{% endfor %}
ファイルを保存して閉じます。
ここに、POSTリクエストをdelete()ビュー関数に送信するWebフォームがあります。 todo['_id']を渡して、削除するToDoを指定します。 Webブラウザーで使用可能なconfirm()メソッドを使用して、要求を送信する前に確認メッセージを表示します。
インデックスページを更新すると、各Todoアイテムの下に DeleteTodoボタンが表示されます。 それをクリックして、削除を確認します。 インデックスページにリダイレクトされ、todoは表示されなくなります。
これで、FlaskアプリケーションのmongoDBデータベースから不要なToDoを削除する方法があります。
削除を確認するには、mongoシェルを開き、find()関数を使用します。
db.todos.find()
削除したアイテムがtodosコレクションに含まれていないことがわかります。
結論
MongoDBデータベースと通信するtodoを管理するための小さなFlaskWebアプリケーションを構築しました。 MongoDBデータベースサーバーに接続する方法、ドキュメントのグループを格納するコレクションを作成する方法、コレクションにデータを挿入する方法、コレクションからデータを取得および削除する方法を学習しました。
Flaskの詳細については、Flaskを使用してWebサイトを作成する方法シリーズの他のチュートリアルをご覧ください。
MongoDBの詳細については、MongoDBチュートリアルシリーズでデータを管理する方法を参照してください。