Django入門: モデルの作成 ~ 簡単な一行掲示板アプリを作る その8【Windows10】

85, 2020-10-21

目次

はじめに

この記事は「Djangoで一行掲示板を作る」というシリーズの記事です。

前回までにDjangoのプロジェクトとアプリを作成し、ビューからテンプレートを描画し、DBのマイグレーションを行い、動作テストを行いました。

今回から実際に掲示板のためのモデルを定義してマイグレーションを行っていきます。

前提としてOSはWindowsでコマンドプロンプトを使います。
仮想環境を使っているのでvenv\Scripts\activateをアクティベートしています。
仮想環境については第一回の記事をご覧ください。
また初期位置として、プロジェクト内のmanage.pyのあるディレクトリに移動してある前提です。

モデルはいつ作るのか?

ところでモデルはいつ作るべきなのでしょうか?
基本的にはモデル作成の優先度は高いのが普通です。
つまり、プロジェクトの初期の段階でモデルを作るのがよくある方法です。

今回のシリーズではルート情報からビュー、そしてテンプレート、DBの初期マイグレーションという風に進んでいますが、別にこれはモデルの作成を一番最初にやってもかまいません。
このシリーズでは最初に「Hello, World!」を表示するためにこの手順で進んでますが、実際の開発では臨機応変に好きなところから開発を進めます。

また、開発を進めるとモデルが必要になる時がやってきますので、その時に作成するというのもありです。

掲示板のモデルの要件

今回作っているのは一行掲示板です。
ということは掲示板の利用者の投稿内容を表示できるようにする必要があります。
利用者の投稿内容はDBに保存する必要があるので、この「投稿内容」を表現するモデルが必要になることがわかります。

今回はこの「投稿内容」をPostというモデルを作成して表現したいと思います。
Postには投稿内容を表すcontentというフィールドを作ります。
フィールドとは、モデル内に複数作れるデータを入れる箱のことですね。
Postは変数と言うよりはデータのまとまりを表すものです。
そのまとまりの中にフィールドという実際のデータを入れる箱があるというイメージです。

モデル「Post」の作成

ではmanage.pyのあるディレクトリから作業を開始します。
モデルはアプリのディレクトリ以下のmodels.pymodels\ディレクトリ以下に定義するのが一般的です。
あくまで一般的なので他の場所にモデルを定義することも可能です。

bbs\models.pyをエディタで開くと↓のような内容になっています。

from django.db import models

# Create your models here.

「Create your models here.」、つまり「あなたのモデルをここに作ってね」と書いてあります。
それからfrom django.db import modelsはモデルを作成するのに必要なモジュールをインポートしています。
ではさっそくこのファイル内にモデルを作りましょう。

from django.db import models


class Post(models.Model):
    """
    掲示板への投稿内容
    """
    pass

↑のようにモデルはクラスとして定義します。
クラスはmodels.Modelを継承している必要があります。
クラスの名前は加工されてDB内のテーブルの名前になります。
たとえばアプリ名が「bbs」であれば↑のモデルは「bbs_post」という名前でテーブルが定義されます。
この名前は開発者が変更することも可能です。

さらにモデルPostにフィールドを追加します。

from django.db import models


class Post(models.Model):
    """
    掲示板への投稿内容
    """
    content = models.CharField(max_length=140, help_text='掲示板の投稿内容')

モデル内のフィールドは↑のようにクラスの属性として定義します。
↓を詳しく見てみます。

content = models.CharField(max_length=140, help_text='掲示板の投稿内容')

Djangoにはモデルのフィールドを定義するためのクラスが多数用意されています。
models.CharFieldというのはそのクラスの内の1つです。
このクラスは文字列を扱うためのフィールドです。
引数のmax_lengthはこのフィールドに格納できる最大文字列数を指定します。↑の例では140になっています。
help_textは管理ページに表示するテキストで、サイト管理者にフィールドの役割を説明するための属性です。

これでモデルの定義は完了しました。
簡単ですね。

マイグレーションの実行

モデルを定義したら次はモデルのマイグレーションを行います。
今回作ったモデルは私たちのオリジナルのモデルなので、マイグレーションファイルはまだ作成されていません。
よって最初にmakemigrationsを実行してマイグレーションファイルを作成する必要があります。

manage.pyのあるディレクトリから↓のコマンドを実行すると↓のようなログが表示されます。

> python manage.py makemigrations
Migrations for 'bbs':
  bbs\migrations\0001_initial.py
    - Create model Post

↑のログを見ると「bbs\migrations\0001_initial.py」というマイグレーションファイルが作成されているのがわかります。
このマイグレーションファイルをエディタで開いてみると↓のようになっています。

# Generated by Django 3.1.1 on 2020-09-21 20:06

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Post',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('content', models.CharField(help_text='掲示板のポスト内容', max_length=140)),
            ],
        ),
    ]

クラスMigrationがマイグレーションを実際に実行するスクリプトとなるクラスです。
operationsというリストがありますが、ここにDBを操作するためのオペレーションが入ります。
↑の例ではmigrations.CreateModelというのがそのオペレーションです。

このマイグレーションファイルですが、マイグレーションでエラーが起きた場合などに開発者が直接編集することがあります。

ではマイグレーションファイルを作成したのでマイグレーションを実行しましょう。

> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, bbs, contenttypes, sessions
Running migrations:
  Applying bbs.0001_initial... OK

python manage.py migrateでマイグレーションを実行すると↑のように「bbs.0001_initial... OK」と表示されます。
先ほどのマイグレーションファイルの実行が成功したようです。

では試しにもう一回マイグレーションを実行してみてください。

> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, bbs, contenttypes, sessions
Running migrations:
  No migrations to apply.

今度は↑のように表示されます。
「No migrations to apply.」、つまり「適用するマイグレーションはありません」と表示されます。
このようにDjangoでは実行したマイグレーションを記録して管理しています。
そのため一度実行したマイグレーションは再度実行されないようになっています。
この記録はDB内のdjango_migrationsというテーブルで管理されています。

DBの中身を見てみる

ここからは余談ですが、DBの中身を見てみたいと思います。
ただしこれは、環境にsqlite3が入っている人限定の余談です。
環境でsqlite3が使える場合はmanage.pyのあるディレクトリから↓のようにコマンドを実行すると、sqlite3db.sqlite3をオープンすることが出来ます。

> sqlite3 db.sqlite
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
sqlite>

sqlite3のコマンドラインから↓のようにコマンドを実行すると、DB内のテーブルの一覧を表示できます。

sqlite> .tables
auth_group                  bbs_post
auth_group_permissions      django_admin_log
auth_permission             django_content_type
auth_user                   django_migrations
auth_user_groups            django_session
auth_user_user_permissions

↑の内、bbs_postというのが今回作成したモデルです。
django_migrationsのレコードを見てみます。

sqlite> select * from django_migrations;
1|contenttypes|0001_initial|2020-09-20 21:02:09.629999
2|auth|0001_initial|2020-09-20 21:02:09.712794
3|admin|0001_initial|2020-09-20 21:02:09.805690
4|admin|0002_logentry_remove_auto_add|2020-09-20 21:02:09.899446
5|admin|0003_logentry_add_action_flag_choices|2020-09-20 21:02:10.006855
6|contenttypes|0002_remove_content_type_name|2020-09-20 21:02:10.096771
7|auth|0002_alter_permission_name_max_length|2020-09-20 21:02:10.182166
8|auth|0003_alter_user_email_max_length|2020-09-20 21:02:10.281426
9|auth|0004_alter_user_username_opts|2020-09-20 21:02:10.382155
10|auth|0005_alter_user_last_login_null|2020-09-20 21:02:10.483390
11|auth|0006_require_contenttypes_0002|2020-09-20 21:02:10.566693
12|auth|0007_alter_validators_add_error_messages|2020-09-20 21:02:10.665567
13|auth|0008_alter_user_username_max_length|2020-09-20 21:02:10.757945
14|auth|0009_alter_user_last_name_max_length|2020-09-20 21:02:10.848351
15|auth|0010_alter_group_name_max_length|2020-09-20 21:02:10.964376
16|auth|0011_update_proxy_permissions|2020-09-20 21:02:11.054930
17|auth|0012_alter_user_first_name_max_length|2020-09-20 21:02:11.140816
18|sessions|0001_initial|2020-09-20 21:02:11.227002
19|bbs|0001_initial|2020-09-21 20:12:04.857470

↑の↓の行を見るとわかりますが、しっかりと今回のマイグレーションが記録されています。

19|bbs|0001_initial|2020-09-21 20:12:04.857470

次にbbs_postのテーブルの定義を見てみます。

sqlite> .schema bbs_post
CREATE TABLE "bbs_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "content" varchar(140) NOT NULL);

↑を見ると、idcontentが定義されているのがわかります。
idですが、Djangoのモデルは自動でidというフィールドをテーブルに定義します。このフィールドはテーブルのプライマリーキーとして利用されます。

おわりに

今回は掲示板用のモデルを作成しました。
次回から今回作ったモデルを使ったコードを書いていきたいと思います。

来週へ続く