Django と MongoDB の接続方法
最も一般的なウェブフレームワークの 1 つである Django は「電池付属」の考えを採用しています。 つまり、拡張機能やその他のフレームワークを使用せずに普通の Django のみで本番対応のアプリケーションをビルドすることができます。 SQLite データベースでさえも、初期状態で使用できるほどです。 SQLite は学習用と小規模のアプリケーションの開発に最適なデータベースですが、プロジェクトの規模が大きくなるにつれて問題が発生しやすくなる特定の制限があります。
開発者はアプリを拡張して負荷の高い演算を実行できるようにする場合、SQLite ではなく他のデータベースを選択する傾向にあります。 Django は PostgreSQL、MariaDB、MySQL、Oracle、SQLite、一部のサードパーティデータベースバックエンドなどの多数のデータベースを公式にサポートしていますが、 MongoDB はサポート対象に含まれていません。ただし、2023 年に JetBrains が実施した Django 開発者アンケートによると、これは依然として Django 開発者の 8% が使用している非常に一般的な選択肢です。
MongoDB を必要とする開発者とその理由
Django プロジェクトに MongoDB を選択する理由とは何でしょうか?また、Django が正式にこのデータベースをサポートしていないことは実際にどのような意味があるのでしょうか? 確認していきましょう。
正式にサポートされているデータベースはどれもリレーショナルデータベース管理システム(RDBMS)です。つまり、データをテーブルに格納して、SQL(構造化クエリ言語)をサポートしています。 一方、MongoDB は非リレーショナルデータベースです。 このようなデータベースは往々にして NoSQL とも呼ばれており、 行と列のテーブルではなく、BSON という JSON に似た形式でデータを格納します。
非リレーショナルデータベースである MongoDB には、主に以下の点で SQL データベースを使う以上のメリットがあります。
- スキーマがない: 時間が経つにつれて構造の変更が必要となる可能性のある複雑なデータを保存する必要がある場合、BSON の柔軟性が非常に役立ちます。
- ドキュメントモデル: データの形式をドキュメントごとに変更できるため、階層データの保管や多様な非構造化データに最適です。
- 拡張性: MongoDB は水平方向に拡張できるように設計されており、大量のデータと高負荷を処理できるシャーディングをサポートしています。
- リアルタイム処理: MongoDB では変更ストリームをサブスクライブすることで、アプリケーションがほぼ瞬時にデータの変更に反応できます。
これらのメリットを考慮し、開発者はユーザー生成コンテンツを処理するブログプラットフォームやアプリケーション、IoT(モノのインターネット)、ビッグデータサービス、およびモバイルアプリケーションによく MongoDB を好んで使用しています。
ただし、MongoDB は SQL データベースを簡単に置き換えるものではなくことを理解しておくことが重要です。 Django は MongoDB をネイティブでサポートしていないため、サードパーティパッケージを統合してコードベースを適宜に調整する必要があります。 さらに、以下の制限を考慮して開発プロセス全体を整理する必要があります。
- Django に組み込まれている SQL 指向 ORM は MongoDB では使用できません。
- Django の管理インターフェースを通じてコンテンツを管理できなくなります。
- データベースと連携することを想定したその他多数の Django 機能を使用できなくなります。 MongoDB を使用すると「Django の流儀」から確実に離れてしまいます。
コードが多いほど、より多くの変更が必要となります。 このため、プロジェクトのライフサイクルの非常に早い段階で MongoDB に切り替える方が合理的と言えます。
このチュートリアルでは、非常に基本的な Django プロジェクトと MongoDB の接続を 2 つの方法で行います。
- MongoEngine を使用する方法(PyMongo を基盤とするエンジン)
- PyMongo のみを使用する方法
要件
作業を開始する前に、以下の項目をインストールする必要があります。
- PyCharm Professional 2023.3(無料 30 日間体験版を利用できます)
- Python
- Docker(コンテナーで MongoDB を実行する場合のみ)
以下の Python パッケージとソフトウェアのインストール手順はチュートリアルの中で提供されます。
- MongoDB Community(ローカルインストールの場合のみ)
- Django
- PyMongo
- MongoEngine
Django プロジェクトの準備
基本的な Django の ToDo リストアプリケーションを含むプロジェクトを使用します。 プロジェクトを新規に作成する場合は、PyCharm ドキュメントにあるこちらのチュートリアルをご覧ください。 そうでない場合は、以下のようにしてリポジトリをクローンしましょう。
- PyCharm を起動し、「ようこそ」画面の Get from VCS(VCS から取得)をクリックします。
- リポジトリの URL を挿入し、Clone(クローン)をクリックします。
PyCharm がプロジェクトをダウンロードし、システムインタープリターを構成します。 このチュートリアルでは、ローカルの virtualenv インタープリターを使用します。これもセットアップが必要です。
プロジェクトをクローンした直後に表示されるポップアップで、Configure a Python interpreter(Python インタープリターの構成)をクリックします。 または、右下のインタープリターセレクターをクリックして、Add New Interpreter(新規インタープリターの追加)| Add Local Interpreter(ローカルインタープリターの追加)を選択します。 PyCharm でのインタープリターの構成の詳細については、ドキュメントをご覧ください。
インタープリターを構成したら、Python Packages (Python パッケージ)ツールウィンドウを開いて Django をインストールします。
MongoDB のインストール
Django プロジェクトの準備ができたので、MongoDB データベースのプロビジョニングが必要です。 プロジェクトに最適な内容に合わせて以下の 3 つのオプションから 1 つを使用できます。
MongoDB Atlas のセットアップ
Django プロジェクトをクラウドの MongoDB データベースに接続する場合は、MongoDB Atlas に登録し、そこで無料のデータベースクラスターをデプロイします。 アプリケーションからこのクラスターにアクセスするには、接続 IP アドレスを IP アクセスリストに追加し、データベースユーザーを作成する必要もあります。 このチュートリアルの次の手順では、接続文字列が必要となります。 以下のようにして取得してください。
- データベースを選択します。
- Overview(概要)タブの Connect(接続)をクリックします。
- Drivers(ドライバー)を選択します。
詳細については、MongoDB Atlas のドキュメントをご覧ください。
Docker コンテナーで MongoDB を実行する
コンテナーで MongoDB Community Edition を実行することにした場合は、以下の手順を実行します。
- MongoDB Docker イメージをプルします。
docker pull mongodb/mongodb-community-server
- イメージをコンテナーとして実行します。
docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest
詳細については、MongoDB ドキュメントをご覧ください。
MongoDB をローカルにインストールする
MongoDB をローカルデータベースとして実行することにした場合は、以下の手順を実行します。
- MongoDB Community Edition をインストールします。
- MongoDB シェルを起動してデータベースを作成します。
% mongosh > use djangoTutorial
データソースの構成
この手順は必須ではありません。 データソースを構成すると、ソフトウェアを追加インストールしたり、MongoDB Atlas のウェブインターフェースを開いたりせずに、PyCharm でデータベースコレクションを直接表示して変更を追跡できます。
PyCharm に戻り、Database(データベース)ツールウィンドウを開き、「+」をクリックしてデータソースの作成を開始します。 データソースのタイプに MongoDB を選択します。
新しく作成されたデータソースを構成します。 MongoDB Atlas を使用している場合は、接続文字列を URL フィールドに入力し、データベースユーザーの資格情報を入力します。
MongoDB Community を使用している場合は、ローカルにインストールされているか Docker コンテナーで実行するかに関係なく、以下のようにしてデータソースを構成します。
- インストール中にデフォルト設定を変更した場合は、データベースホストアドレスとポート番号を入力します。 そうでない場合は、手順 2 に進みます。
- ユーザー名とパスワードを構成した場合は、対応するフィールドにそれらを入力します。 そうでない場合は、Authentication(認証)で No auth(認証なし)を選択します。
- Database(データベース)フィールドでデータベース名を指定します。
- Test Connection(接続のテスト)をクリックします。
PyCharm での詳細な MongoDB データソースの構成方法については、ドキュメントをご覧ください。
環境変数の構成
ユーザー名とパスワードの認証で MongoDB Atlas またはローカルの MongoDB データベースを使用している場合は、環境変数を使って資格情報を保存する .env ファイルを作成する必要があります。 これは、プロジェクトをバージョン管理対象にする際に機密データの漏えいを防止するためのベストプラクティスです。
- プロジェクトのルートディレクトリを右クリックし、コンテキストメニューから New(新規)| File(ファイル)を選択します。
- ファイル名に .env を指定します。
- 新しく作成されたファイルがエディターで開きます。 環境変数と値を追加します。 以下のような例が挙げられます。
USERNAME=jetbrains PASSWORD=czUfHKhGNxtGTsv HOST=cluster0.bqnh3eo.mongodb.net
HOST
は MongoDB Atlas のみに必要です。
- エディターの任意の場所を右クリックし、コンテキストメニューから Git | Add to .gitignore(.gitignore に追加)を選択します。
次に、新しく作成された .env ファイルが Django サーバーを起動するたびに読み込まれるように実行構成を構成する必要があります。
- 上部の Run(実行)ウィジェットをクリックし、メニューから Edit Configurations(構成の編集)を選択します。
- Paths to “.env” files(”.env” ファイルへのパス)フィールドに .env へのパスを指定します。
- 準備が完了したら、OK または Run(実行)をクリックします。
選択した Django と MongoDB の接続方法を使用できるようになりました(または両方を試すことができます)。
MongoEngine を使用した Django と MongoDB の接続
MongoEngine は Django プロジェクト用の Python Object-Document Mapper(ODM)です。 リレーショナルデータベースの ORM(オブジェクトリレーショナルマッピング)と同様に機能します。 MongoEngine による MongoDB と Django の接続には、主に以下のようなメリットがあります。
- ODM では使い慣れた構文でコード内にドキュメントのスキーマを定義できます(Django を SQL データベースで使用する際のモデルと同様)。
- データベースクエリに使用できる充実した「Python らしい」構文。
- Django フォームと Django Rest フレームワークのシリアライザーをサポート。
要するに、MongoEngine では Django プロジェクトで MongoDB を高いレベルで操作できるのです。 既存の Django プロジェクトを MongoDB を使用するプロジェクトに変換する必要がある場合に最適な選択肢とも言えます。
MongoEngine のインストールと有効化
まずは、 Python Packages(Python パッケージ)ツールウィンドウで MongoEngine パッケージのインストールを始めましょう。 ツールウィンドウを開き、mongoengine と入力して、Install(インストール)をクリックし、バージョンを選択します。
デフォルトでは、Django プロジェクトは SQLite データベースを使用して作成されます。 settings.py の DATABASES セクションをコメントアウト(または削除)して SQLite データベースを無効にする必要があります。 ⌥⌘O / Ctrl+Alt+Shift+N を押して DA… と入力し始めると、このセクションへすぐにアクセスできます。
代わりに、以下を settings.py に追加します。
import mongoengine mongoengine.connect(db="djangoTutorial", host="mongodb://localhost:27017/")
MongoDB Atlas の場合は、.env ファイルからユーザー名とパスワードを読み込みます。 以下のような例が挙げられます。
import os import mongoengine USERNAME = os.getenv("USERNAME") PASSWORD = os.getenv("PASSWORD") HOST = os.getenv("HOST") mongoengine.connect(db="djangoTutorial", host=f"mongodb+srv://{HOST}/", username=USERNAME, password=PASSWORD)
モデルの編集
MongoDB はスキーマレスではありますが、MongoEngine ではアプリケーションレベルでスキーマを定義できます。 このようなスキーマはデータベースには渡されませんが、Django と MongoDB 間の連携に別のレベルの抽象化を追加することで、開発者がより簡潔で保守しやすいコードを書くことができます。
Django ORM とは異なり、MongoEngine はモデルの代わりにドキュメントを使用します。 残念ながら、MongoEngine ドキュメントは Django の管理インターフェースではサポートされていません。 Django サーバー起動時のエラーを回避するには、対応するクラスをコメントアウトまたは削除して admin.py の ToDoItem
の登録を解除してください。
Django Structure(Django 構造)ツールウィンドウを使うと、モデルの管理クラスに素早くアクセスできます。
Django Structure (Django 構造)ツールウィンドウで Models に含まれる ToDoItem をダブルクリックし、エディターでモデルを開きます。 以下のように置換します。
元 | 置換 |
---|---|
from django.db import models |
from mongoengine import Document, fields または
|
models.Model |
ドキュメント |
models.CharField |
fields.StringField() |
models.DateField |
fields.DateField |
以下のようになります。
from mongoengine import Document, fields from django.utils import timezone class ToDoItem(Document): text = fields.StringField(max_length=100) due_date = fields.DateField(default=timezone.now) def __str__(self): return f"{self.text}: due {self.due_date}"
手動置換を避けるため、PyCharm の AI Assistant にこの作業を任せることができます。
- models.py でコードを選択します。
- コンテキストメニューから AI Actions(AI アクション)| New Chat Using Selection(選択項目を使用して新規チャットを開く)を選択します。
- たとえば、Modify the code for usage with MongoEngine(MongoEngine で使用できるようにコードを変更)のようにプロンプトを入力します。
AI Assistant の詳細な使用方法については、PyCharm ドキュメントをご覧ください。
ToDoItem
ドキュメントのインスタンスを作成し、それをデータベースに保存してソリューションをテストしてみましょう。 Python コンソールを開き、以下を実行します。
from todo.models import ToDoItem from datetime import datetime task = ToDoItem(text="Fix the table") task.due_date = datetime(2023,11,29) task.save()
クラウドデータベースを使用している場合、この操作にはしばらく時間がかかる場合があります。 [SSL: CERTIFICATE_VERIFY_FAILED]
エラーが発生した場合は、トラブルシューティングに関する推奨事項をご覧ください。
Database(データベース)ツールウィンドウで to_do_item コレクションを開き、レコードが追加されていることを確認します。
この変更でアプリケーションが壊れていないことを確認しましょう。 PyCharm が自動的に作成した Django サーバー構成を起動します。
次に、ブラウザーで http://localhost:8000/todo/ にアクセスします。
おめでとうございます! Django アプリが MongoDB を使用しています!
PyMongo を使用した Django と MongoDB の接続
PyMongo は MongoDB 用に正式に推奨されている低レベルドライバーです。 Django と MongoDB を直接的に詳細な方法で連携させます。 PyMongo はパフォーマンスを改善するためにデータベースクエリを作成する必要があり、コードベースで ORM のようなエクスペリエンスを必要としない場合に最適な選択肢です。
PyMongo のインストールとモデルの削除
MongoEngine は PyMongo を内部的に実行します。 そのため、このチュートリアルの前の部分を実行した場合はすでにプロジェクト環境に pymongo
がインストールされています。 そうでない場合は、Python Packages(Python パッケージ)ツールウィンドウでインストールしてください。
settings.py の DATABASES
セクションをコメントアウトして SQLite を無効にし、admin.py から ToDoItemAdmin
を削除しましょう(まだ行ってない場合)。
最後に、models.py から ToDoItemAdmin
を削除します。 Recent Files(最近のファイル)(⌘E / Ctrl+E)を使用すると、すぐにアクセスできます。
ビューの変換
Django モデルを使用しなくなったため、それに合わせてビュークラスを変更する必要があります。 views.py に移動し、MongoDB データベースへのアクセスに使用される関数を追加します。
from pymongo import MongoClient def get_db_handle(): client = MongoClient(host="mongodb://localhost", port=27017) db_handle = client.djangoTutorial.to_do_item return db_handle
MongoDB Atlas または認証付きのローカルデータベースの場合は、環境変数を読み込んで接続文字列を使用する必要があります。 以下のような例が挙げられます。
from pymongo import MongoClient import os USERNAME = os.getenv("USERNAME") PASSWORD = os.getenv("PASSWORD") HOST = os.getenv("HOST") def get_db_handle(): client = MongoClient(f"mongodb+srv://{USERNAME}:{PASSWORD}@{HOST}/?retryWrites=true&w=majority") db_handle = client.djangoTutorial.to_do_item return db_handle
この関数は to_do_item
MongoDB コレクションを返します。 MongoDB のメリットの 1 つに、このコレクションが存在しない場合でも最初の挿入時に作成されるということがあります。
ToDoItem
モデルがなくなってしまったため、ビューの AllToDos
と TodayToDos
クラスの get_queryset
メソッドを更新しなければなりません。
class AllToDos(ListView): template_name = "todo/index.html" def get_queryset(self): db = get_db_handle() results = db.find() return results class TodayToDos(ListView): template_name = "todo/today.html" def get_queryset(self): db = get_db_handle() today = datetime.combine(date.today(), time()) results = db.find({"due_date": today}).sort("due_date") return results
このようにコードを変更することで、Django の ListView
クラスのデフォルトの get_queryset
メソッドをオーバーライドしています。 このコードは以下を行います。
AllToDos
クラス:
get_db_handle
を呼び出してdjangoTutorial
データベースからto_do_item
コレクションを取得し、それをdb
に割り当てます(5 行目)。- PyMongo のコレクションの
find()
メソッドを適用し、コレクションのすべての項目をフェッチします(6 行目)。
TodayToDos
クラス:
- 現在の日付とデフォルトの時間(午前 0 時)を組み合わせて
today
に設定します。 アプリケーションに時刻は必要ありませんが、BSON 形式の要件であるため、これを取り除くことはできません(15 行目)。 due_date
が today であるすべての項目をフェッチし、due_date
順に並べ替えます(16 行目)。
インポートの更新も忘れないようにしましょう。 赤の波線がついた datetime
と time()
にマウスポインターを合わせ、Import this name(この名前をインポート)を選択します。 どちらの場合も datetime
からインポートします。
Django サーバーが実行中でなければ起動し、ブラウザーで http://localhost:8000/todo/ にアクセスしてアプリケーションが動作していることを確認します。
開発を進める
この時点で Python コンソールを通じてデータベースにレコードを追加できますが、 アプリケーションのユーザーはコンソールを使用できません。 ブラウザーでデータベースに新しいレコードを追加できるビューを開発する必要があるようです。
ウェブフォームを書き始めましょう。 アプリケーションディレクトリ(todo)に forms.py ファイルを作成し、次のコードを挿入します。
from django import forms from datetime import datetime class ToDoItemForm(forms.Form): text = forms.CharField(max_length=100) due_date = forms.DateField(initial=datetime.now)
このフォームには、text
と due_date
の 2 つのフィールドがあります。 後者は現在の日付になります。
次に、views.py にビューを追加しましょう。 このチュートリアルの冒頭で、Django と MongoDB を使用する場合は多数の Django ショートカットが機能しなくなることを説明しました。 今回は関数ベースのビューを使用し、いくつかの基本的なロジックを手動で定義する必要があります(別のデータベースを使用していれば、単にクラスベースのビューを介して継承できていたロジック)。
PyMongo を使用して Django を MongoDB に接続している場合、関数コードは以下のようになります。
from django.shortcuts import redirect, render from .forms import ToDoItemForm ... def add_todo(request): if request.method == "POST": form = ToDoItemForm(request.POST) if form.is_valid(): new_todo = { "text": form.cleaned_data["text"], "due_date": datetime.combine(form.cleaned_data["due_date"], time()) } db = get_db_handle() db.insert_one(new_todo) return redirect('today') else: form = ToDoItemForm() return render(request, "todo/add.html", {"form": form})
詳細は以下のとおりです。
add_todo
ビューが POST リクエストを受け取ると、ToDoItemForm
データをform
に割り当てます(6~7 行目)。- 最初に、投稿したフォームデータが有効であることを確認してから、フォームデータから辞書を作成します(8~12 行目)。
get_db_handle
メソッドを通じて MongoDB に接続し、新しいレコードをデータベースに挿入します(13~14 行目)。- POST リクエストでない場合は、単に空のフォームが返されます(16 行目)。
MongoEngine を使用している場合は、MongoEngine ドキュメントに提供されている組み込みの save()
メソッドを使用できるため、コードはより短くなります。
from django.shortcuts import redirect, render from .forms import ToDoItemForm ... def add_todo(request): if request.method == "POST": form = ToDoItemForm(request.POST) if form.is_valid(): new_todo = ToDoItem(text=form.cleaned_data["text"], due_date=form.cleaned_data["due_date"]) new_todo.save() return redirect("today") else: form = ToDoItemForm() return render(request, "todo/add.html", {"form": form})
return ステートメントのテンプレートファイル add.html への参照が黄色い波線でハイライトされます。 そこにマウスポインターを合わせ、Create template todo/add.html(テンプレート todo/add.html の作成)を選択します。
エディターでテンプレートが開きます。 そのテンプレートに以下の HTML コードを入力します。
{% extends "base.html" %} {% block content %}
Add new to-do:
{% endblock %}
新しいタスクを作成するためのボタンを追加して、base.html を更新します。
ブラウザーでページにアクセスしてタスクを追加できるように、todo/urls.py を更新します。
urlpatterns = [ path("", views.AllToDos.as_view(), name="index"), path("today/", views.TodayToDos.as_view(), name="today"), path("add/", views.add_todo, name="add") ]
最後に、この新しい機能をブラウザーで試してみましょう! http://localhost:8000/todo/add/ にアクセスしてタスクを追加しましょう。
まとめ
このチュートリアルのすべての手順を実行した場合は、PyMongo と MongoEngine の 2 つのライブラリを使用して基本的な Django プロジェクトを MongoDB に正しく接続できたことでしょう。
すでにご存じのとおり、MongoEngine は実際に PyMongo をベースとしています。 では、その違いは何でしょうか。また、Django プロジェクトに適切な方法を選択するにはどうすればよいのでしょうか。 以下のテーブルに、それぞれのメソッドのメリットとデメリットをまとめました。
MongoEngine | PyMongo | |
---|---|---|
コレクションへのアクセス | Document クラスがコレクションにマップされる |
コレクションは MongoClient を通じてアクセス可能 |
クエリの実行 | 連鎖したクエリ: ToDoItem.objects.filter(due_date=date.today()) |
辞書式のクエリ: db.find({"due_date": today}).sort("due_date") |
パフォーマンス | オブジェクトドキュメントマッピングによりやや遅め | Python 辞書をデータモデルとして使用しているため高速 |
使用難易度 | 追加の抽象化レベルと ORM のようなエクスペリエンスの提供によって容易に使用できるようになっている | MongoDB の内部形式をより深く理解する必要がある |
よくある質問
Django および MongoDB とは?
Django と MongoDB はどちらもウェブ開発で使用されますが、用途が異なります。 Django は MVT(モデルビューテンプレート)アーキテクチャパターンと DRY(「Don’t Repeat Yourself」)の原則に従う高レベルの Python ウェブフレームワークです。
MongoDB は Django に適していますか?
Django は SQL データベース向けに最適化されています。 NoSQL データベースである MongoDB は MongoEngine や PyMongo といったツールを介して統合することは可能ですが、複雑さが増し、一部のネイティブな Django の機能が制約されてしまいます。 その一方、MongoDB には柔軟なデータ構造や適度な水平方向の拡張性といったメリットが備わっています。 Django に MongoDB を使用するかどうかは、ユーザーの特定のプロジェクトのニーズと追加で発生しうる開発上の課題に対応する準備ができているかどうかによって決める必要があります。
Django と NoSQL を一緒に使用できますか?
はい。MongoDB などの NoSQL データベースを Django と一緒に使用することはできます。 ただし、これにより複雑さが増し、SQL データベース用に最適化された Django の機能が一部制限される可能性があります。 この選択は、特定のプロジェクトの要件とトレードオフに基づいて決定する必要があります。
PyMongo と MongoEngine ではどちらが優れていますか?
PyMongo はより高速であり、MongoDB により直接的にアクセスできますが、MongoDB の内部構造をより深く理解している必要があります。 MongoEngine はより高いレベルのインターフェースを提供し、Django に十分に適合しますが、すべての MongoDB 機能がサポートされていない可能性があるため、抽象化によって低速になる可能性があります。
SQL でなく MongoDB を Django と一緒に使用する理由は?
MongoDB のスキーマの柔軟性、大量のデータを処理できる能力、およびネストオブジェクトなどの独特の機能があるため、特定の Django プロジェクトでは MongoDB が適しています。 複数のサーバーで効率よく拡張することも可能です。 ただし、それを使用することで Django に組み込まれている SQL データベース用に最適化された機能が一部制限されてしまう可能性があります。
有益なリンク集
ドキュメント
- PyCharm での Django のサポート
- Django Structure ツールウィンドウ
- MongoDB のドキュメント
- MongoEngine のドキュメント
- PyMongo のドキュメント
チュートリアル
動画
ポッドキャスト
その他
- What is the Django Web Framework?(Django ウェブフレームワークとは?)
- NoSQL とは?
- Django と MongoDB を使用する前にこちらをお読みください
オリジナル(英語)ブログ記事の作者: