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チュートリアルシリーズでデータを管理する方法を参照してください。