前回はDjangoプロジェクトの作成から、自分の書いたHTMLファイルをブラウザで表示するところまで行いました。今回はDjangoのアーキテクチャ(全体像)を説明し、「モデル」と呼ばれるデータを管理する機能について解説します。
Djangoのアーキテクチャ
前回はあらかじめ用意したHTMLファイルを表示するのみでしたが、実際のアプリケーションでは条件に応じて表示するものを出し分けることが要求されます。HTMLファイルのように内容が変わらない情報のことを静的コンテンツと呼ぶのに対し、ユーザのリクエストに応じて内容が変わる情報を動的コンテンツと呼びます。動的コンテンツを配信する仕組みをこれから作っていくわけです。
多くのアプリケーションでは、情報をデータベースと呼ばれるデータの保管場所に保存し、必要に応じてデータを取り出して利用します。HTMLにはデータベースを操作する機能がないため、webページとデータベースを仲介する機能が必要になります。
この仕組みをDjangoでは、モデル テンプレート ビュー URLディスパッチャというコンポーネントに分割して実現します。ユーザのリクエストを受け取ってからレスポンスを返す流れを説明します。
- ユーザからのリクエストをURLディスパチャが受け取り、その情報をビューに渡す
- ビューは、リクエストの内容に応じてモデルを呼び出す
- モデルは、ビューからの命令に従って、データベースに接続し、データの挿入/抽出及びデータの整形を行い結果をビューに返す
- ビューはその結果をテンプレートに渡す
- テンプレートは渡されたデータを所定の枠にはめ込むことでページを作成し、URLディスパッチャに返す
- URLディスパッチャは出来たページをユーザにレスポンスする
ざっくり言うと、モデルはデータを管理する担当、テンプレートはページを作成する担当、ビューはモデルとテンプレートを繋げる担当です。このようなDjangoのアーキテクチャは、Model、Template、Viewの頭文字をとってMTVモデルと呼ばれます。
メモアプリ
このチュートリアルではメモアプリを作ることを最初の目標にして進めていきます。メモアプリに必要な以下の機能を実装します。
- メモを作成する
- メモを一覧表示する
- メモの詳細を表示する
- メモを編集する
- メモを削除する
今回はまずメモデータを保存するためのモデルを作成します。
モデルの定義
memo_app/models.pyを編集します。
from django.db import models
class Memo(models.Model):
id = models.AutoField(primary_key=True)
text = models.TextField(null=False)
class Meta:
db_table = 'memos'
Memoクラスを定義しました。models.Modelを継承することでDjangoのモデルとして機能するようになります。このクラスをMemoモデルと呼ぶことにしましょう。このモデルはidとtextの2つの属性を持ちます。”Memo”は”id”と”text”の値を持っている、という概念を作ると言ってもいいでしょう。Memoモデルに属する1つのデータをMemoモデルのオブジェクトと呼びます。ある1つのオブジェクトはidとtextの2つの値を持つことになります。
下図に名称をまとめてみました。定義したモデルに従ってデータベースにテーブルが作成されるため、対応関係も載せました。

idはMemoモデルの中の1つ1つのデータに対して振られる連番のことです。id = models.AutoField(primary_ley=True)はどんなモデルにも付けるのでテンプレだと思ってください。こう定義することで勝手にidを振ってくれます。
textはメモの本文である文字列データのことです。TextFieldにすることで(長い)文字列として扱ってくれます。null=Falseはtextの値を空白にすることを禁止するオプションです。
下のdb_table='memos'ではデータベースにテーブルを作成する際のテーブル名を指定しています。指定しなくてもテーブル名は自動で付きます(が少々気に入らないのでいつも指定しています)。
models.AutoFieldやmodels.TextFieldのようなフィールドや、(null=False)のようなフィールドオプションは他にもまだあるので、必要に応じて調べて使うようにしましょう。
Django: モデルフィールドリファレンスの一覧 - Qiita
モデルの作成
memo_app/models.pyのモデル定義に従って、データベースにテーブルを作成します。データベースを操作する必要はなく、Djangoが提供するコマンドを打つことで行います。2ステップあります。
マイグレーションファイルの生成
$ python manage.py makemigrations
Migrations for 'memo_app':
memo_app/migrations/0001_initial.py
- Create model Memo
このコマンドを実行すると、モデルファイルが読み込まれ、マイグレーションファイルというファイルが生成されます。今、memo_app/migrations/0001_initial.pyが生成されました。
この時点ではまだデータベースは変更されていません。次のコマンドを打つと変更されます。
マイグレート
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, memo_app, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying memo_app.0001_initial... OK
Applying sessions.0001_initial... OK
このコマンドを打つことで、マイグレーションファイルの内容を実際にデータベースに反映させます。最初の実行時にはDjangoがデフォルトで提供するユーザや権限などに関する内容も反映されます。
管理画面
Memoモデルが作成されたことを確認する方法はいくつかあるのですが、管理画面を見るのが分かりやすいかなと思います。
memo_app/admin.pyを編集します。
from django.contrib import admin
from .models import Memo
admin.site.register(Memo)
サーバを起動してブラウザでlocalhost:8000/adminを開くと、ログイン画面が出てきます。
$ python manage.py runserver
まだユーザを作っていないのでログインできません。管理者用ユーザを作成しましょう。一回サーバを停止して以下のコマンドを打ちます。ユーザ名、メールアドレス、パスワードを入力しましょう。
$ python manage.py createsuperuser
# ユーザ名、メールアドレス、パスワードを入力する
再度サーバを起動し、ユーザ名とパスワードを入力してログインしましょう。
これが管理画面です。Djangoが勝手に作ってくれています。Memosがadmin.pyで登録したMemoモデルです。Memosをクリックし、'MEMOを追加'ボタンを押すとフォーム画面が出てきます。Textフォームに適当に文字を入力して保存すると、オブジェクトが作成されます。編集や削除もできます。試しにオブジェクトを3つくらい作成しておきましょう。
メモ一覧ページの作成
では、Memoモデルに保存されているオブジェクトの一覧を表示するページを作成していきましょう。まず、memo_app/views.pyに新たな関数を追加します。
from django.shortcuts import render
from .models import Memo
def index(request):
return render(request, 'index.html', {'text': 'This page is a memo_app/index'})
# ↓追加
def list_view(request):
return render(request, 'memo_list.html', {'memos': Memo.objects.all()})
render関数は前回の記事で出てきましたね。第2引数にテンプレート、第3引数にテンプレートに渡す辞書を指定します。
Memo.objects.all()はMemoモデルから全てのオブジェクトを取得することを意味します。この書き方は後ほど詳しく見ることにして、保存してあるオブジェクトのリストが返されると思ってください。
次にmemo_list.htmlを作成します。
<!DOCTYPE html>
<html lang=“ja”>
<head>
<meta charset=“utf-8”>
<title>memo_app</title>
</head>
<body>
<h1>Memo List Page</h1>
{% for memo in memos %}
<p>{{ memo.id }} {{ memo.text }}</p>
{% endfor %}
</body>
</html>
このテンプレートではビューからmemosという変数名でMemoモデルのオブジェクトリストを受け取っています。これを表示するのですが、Djangoにはhtmlファイルでpython風なコードを書くことができるテンプレートエンジン(Jinja2)という機能が備わっています。ただしpythonのようにいろいろな処理はできず、決められた書き方に従う必要があるので注意です。memosはリスト(正確にはQuerySet)なのでfor文を回し、各オブジェクトのidとtextの値をpタグで表示します。
最後にmemo_app/urls.pyでurlを定義します。
from django.urls import path
from . import views
app_name ='memo_app'
urlpatterns = [
path('index/', views.index, name='index'),
path('memo_list/', views.list_view, name='memo_list') # 追加
]
サーバを起動し、localhost:8000/memo_app/memo_listを開いてみましょう。一覧で表示されたでしょうか。
データベース操作
データベースにデータを挿入したり抽出したりするためには、本来はSQLという言語を使う必要があります。しかし開発する際にSQLは扱いづらいため、データベースの操作を簡単に実行できる仕組みがよく導入されます。これをORマッパー(Object-relational mapping)と呼びます。
DjangoでもモデルマネージャーというORマッパーが用意されています。
ORマッパーを試すために、djangoシェルという機能を使いましょう。以下のコマンドを打つとシェルが起動します。
$ python manage.py shell
ここではpythonのインタラクティブモードと同じようにpythonを実行することができます。試しに以下を実行してみましょう。
In[1]ではMemoモデルをインポートしています。
In[2]はviews.pyで書きましたね。.all()は全てのオブジェクトが返ってきます。.objectsは決まり文句ですので気にしなくてOKです。返り値がQuerySetになっていますが、とりあえずはリストだと思ってもらって大丈夫です。
In[3]ではリストのように[0]で1つ目の要素を取り出せていますね。各要素はオブジェクトなので、オブジェクト.属性で各値を取り出すことができます(In[4], In[5])。
In[6]は.first()で一番最初の要素を取り出しています。これはIn[3]と同じ結果になります。
ある条件を満たすオブジェクトのみを抽出したい時は、.filter(属性=value)を使います。
In[8]ではidが3であるオブジェクトを取得しています。結果がQuerySetであることに要注意です。QuerySetはリストのことなので、In[9]のようにリスト.属性ではエラーになります。In[10]では.first()で最初の要素を取り出すことでオブジェクト.属性を実行することができます。
他にも様々な操作ができるので、ぜひいろいろ試してみてください。
クエリを作成する | Django ドキュメント | Django
QuerySet API reference | Django ドキュメント | Django
今回は最初にDjangoのアーキテクチャ(全体像)を説明し、モデルの作成、管理画面の表示、モデルオブジェクトの表示を行いました。次回はモデルオブジェクトの追加、編集、削除を行うページの作成を行います。
今回のキーワード:
- MTVモデル(モデル、テンプレート、ビュー)
- モデルの属性とオブジェクト
- マイグレート
- 管理画面
- テンプレートエンジン
- ORマッパー