FlaskアプリケーションでMongoDBを使用する方法

提供:Dev Guides
移動先:案内検索

著者は、 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にドキュメントのグループを格納するコレクションの作成、コレクションへのデータの挿入、コレクションからのデータの取得と削除などの基本的なタスクを実行します。

前提条件

ステップ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の新規インストールである場合、出力には、adminconfig、および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チュートリアルシリーズでデータを管理する方法を参照してください。