Djangoチュートリアル③（モデルの作成、Django Admin）

# はじめに

[Djangoチュートリアル②（ビューの作成）](https://qiita.com/honda28/items/c91f78238ea3d53e776d)に続いて、アプリを作成してみる。[はじめての Django アプリ作成、その2](https://docs.djangoproject.com/ja/3.1/intro/tutorial02/)、[現場で使える Django の教科書（基礎編）](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Django-%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8%E3%80%8A%E5%9F%BA%E7%A4%8E%E7%B7%A8%E3%80%8B-%E6%A8%AA%E7%80%AC-%E6%98%8E%E4%BB%81/dp/4802094744)を参考にする。

# Database の設定

config/settings.py でデータベースの設定を行う。デフォルト設定では SQLite となっていて、これは Python に標準で組み込まれているため、追加のインストールが必要ない。本番環境では PostgreSQL などを使ったほうがよいとのこと。DB にあまり詳しくないため、ここで一度寄り道して DB について調べる。以下記事を読むに、本番環境だから SQLite がだめとかそういったことはないらしいが、複数の同時書き込みができないようなので個人の範囲を超える使用を考えている場合には向いていなさそうだ。ブログとかその程度のレベルなら問題はないとのこと。
[SQLite を使うべき10の理由と5つのデメリット](http://www.cpa-lab.com/tech/046)、[SQLite 
のデータベースのメリットやデメリットは？](https://www.1-firststep.com/archives/7411) 

話を戻す。config/settings.py の中に DATABASES という項目があり、デフォルトは SQLite の設定で以下のようになっている。

```python:config/settings.py
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
```

NAME はデータベースの名前で SQLite を使用している場合はプロジェクトディレクトリにファイルを保存( polls/db.sqlite3 )する。SQLite 以外の場合は、USER や PASSWORD、HOST などの追加設定をする必要がある。~~PostgreSQL で試したいが、今は一旦置いておくこととする。~~（2021/04/13 追記）
PostgreSQL を試してみた結果を [Djangoで既存のPostgreSQLを利用](https://qiita.com/honda28/items/d5bf743c3c244791f559)に記述。
さらに config/settings.py で TIME_ZONE も設定する。デフォルトでは、LANGUAGE が英語、TIME_ZONE が UTC となっているので、変更しておく。

```python:config/setttings.py
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/

LANGUAGE_CODE = 'ja'  # 'en-us'

TIME_ZONE = 'Asia/Tokyo'  # 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True
```

USE_I18N、USE_L10N、USE_TZ はそれぞれ以下の意味を表している。デフォルトのまま True でよい。

- USE_I18N: 多言語化機能を有効にするかどうか。(I18N = Internationalisation)
- USE_L10N: ローカライゼーション機能を有効にするかどうか。(L10N = Localization)
- USE_TZ:   タイムゾーン変換機能を有効にするかどうか。False だと上記の TIME_ZONE の設定が適用されない

# マイグレーション

データベースを利用するには、__マイグレーション__という操作を行い、データベースとテーブルを作成する必要がある。マイグレーションは以下の2つのコマンドを用いて段階を経て行われる。

- makemigrations : モデルの定義からマイグレーションファイルを作成
- migrate : マイグレーションファイルの内容をデータベースに反映して、テーブルを作成・変更

現段階ではまだモデルを作成していないため、makemigrations を実行してもなにも起きない。そこで migrate のみを実行している。コマンドは以下。

```
$ python manage.py migrage
```

引数無しでコマンドを実行すると、config/settings.py 内で定義されている INSTALLED_APPS に登録されたアプリケーションに対してテーブルが作成される。個別のアプリケーションを限定する場合は引数で指定する。INSTALLED_APPS はデフォルトでは以下のようになっている。

```python:config/settings.py
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',        # 管理サイト
    'django.contrib.auth',         # 認証システム
    'django.contrib.contenttypes', # コンテンツタイプフレームワーク
    'django.contrib.sessions',     # セッションフレームワーク
    'django.contrib.messages',     # メッセージフレームワーク
    'django.contrib.staticfiles',  # 静的ファイル管理フレームワーク
]
```

migrate を実行すると、mysite/db.sqlite3 が作成される（データベースの設定によってディレクトリやファイル名は変わる）。以下コマンドで上記アプリに関するテーブルが作成されていることを確認できる。

```
$ sqlite3 db.sqlite3
sqlite> .tables
```

# モデルの作成

モデルと呼ばれるクラスを作成することで、その定義に対応するデータベースのテーブルとカラムを作成し、データベースのレコードをデータベースのオブジェクトとして扱えるようになる。Object-Relational Mapper という機能が上記の対応したり、データベースの種類による違いなどを吸収してくれるため、データの扱いが容易になる。

モデルクラスは polls/models.py に定義する。このチュートリアルでは、Question と Choice の2つのモデルを作成する。コードは以下。

```python:polls/models.py
from django.db import models


class Question(models.Model):
    class Meta:
        db_table = "polls_question"

    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text


class Choice(models.Model):
    class Meta:
        db_table = "polls_choice"

    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text
```

モデルは django.db.models.Model というクラスを継承して定義する。各クラス内の Meta クラスには対応するテーブル名などの付加情報を、\_\_str__ メソッドにはインタラクティブシェルや管理画面にて表示されるオブジェクトの内容を定義する。（上記では Meta クラスにてテーブル名を 'polls_question' や 'polls_choice' と定義しているが、未定義の場合はデフォルトで <アプリケーション名> _ <モデルのクラス名をスネークケースにした文字列> で表されるので、上記のデータベース名の定義は書かなくても同じデータベース名となる。）\_\_str__ メソッドの有用性は[はじめての Django アプリ作成、その2](https://docs.djangoproject.com/ja/3.1/intro/tutorial02/)の[ API で遊んでみる] に沿って試すとわかる。
各クラスではテーブルのカラムを、クラス属性として Field クラスを用いて定義する。上記では以下のようなクラス属性が定義されている。

- Question : question_text (char 型)、pub_date (date 型)
- Choice : choice_text (char 型)、votes (int 型)

他にも Field クラスや Field オプションが多数あるが、ここでは割愛する。詳細は[モデルフィールドリファレンス](https://docs.djangoproject.com/ja/3.1/ref/models/fields/)を参照。

またテーブルのリレーションを models.ForeignKey で定義する。ForeignKey は多対一のリレーションを定義していて、一般に[一]側のテーブルの主キーを参照する外部キーを[多]側にて設定する。今回の場合は、それぞれの Choice が一つの Question に関連づけられている。他には一対一のリレーションを定義する models.OneToOneField、多対多のリレーションを定義する models.ManyToManyField がある。

# モデルの有効化

上記でモデルを定義したため、マイグレーションの章で説明したように makemigrations コマンドでマイグレーションファイルを作成し、migrate を実行することで作成したモデルの定義をデータベースに反映させる。makemigrations コマンドの前にアプリケーションをプロジェクトに含めるために、config/settings.py の INSTALLED_APPS に追加する。今回の Polls のように自作のアプリケーションの場合は、各アプリケーションディレクトリ直下にある apps.py にかかれている AppConfig （ここでは Polls アプリケーションなので PollsConfig となる）を追加する。PollsConfig は polls/apps.py にあるため、 'polls.apps.PollsConfig' と記述する。

```python:config/settings.py
# Application definition

INSTALLED_APPS = [
    'polls.apps.PollsConfig',      # Polls アプリ
    'django.contrib.admin',        # 管理サイト
    'django.contrib.auth',         # 認証システム
    'django.contrib.contenttypes', # コンテンツタイプフレームワーク
    'django.contrib.sessions',     # セッションフレームワーク
    'django.contrib.messages',     # メッセージフレームワーク
    'django.contrib.staticfiles',  # 静的ファイル管理フレームワーク
]
```

上記で Polls アプリケーションが認識されるので、以下コマンドでマイグレーションを行う。以下では polls を指定しているが、変更がないものは処理されないので引数無しで全体を読み込んでも polls のみの処理となるはず。マイグレーションファイルは polls/migrations ディレクトリに保存される。

```
$ python manage.py makemigrations polls
$ python manage.py migrate 
```

# Django Admin の紹介

ここで Django にデフォルトで入っている管理サイトを触ってみる。まずは管理ユーザーを作成する。以下コマンドを実行し、ユーザー名、メールアドレス、パスワードを設定する。

```
$ python manage.py createsuperuser
```

`$ python manage.py runserver` で開発サーバーを起動し、[http://127.0.0.1:8000/admin/](http://127.0.0.1:8000/admin/) にアクセスすると、管理サイトが表示される。先ほど設定したユーザー名とパスワードでログインすると、様々な操作ができるがここでは割愛する。

# おわりに

[はじめての Django アプリ作成、その2](https://docs.djangoproject.com/ja/3.1/intro/tutorial02/)を進めながら、[現場で使える Django の教科書（基礎編）](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Django-%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8%E3%80%8A%E5%9F%BA%E7%A4%8E%E7%B7%A8%E3%80%8B-%E6%A8%AA%E7%80%AC-%E6%98%8E%E4%BB%81/dp/4802094744)を補助に使って進めた。[現場で使える Django の教科書（基礎編）](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Django-%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8%E3%80%8A%E5%9F%BA%E7%A4%8E%E7%B7%A8%E3%80%8B-%E6%A8%AA%E7%80%AC-%E6%98%8E%E4%BB%81/dp/4802094744)で理解がかなり深まるので助かる。引き続き、[はじめての Django アプリ作成、その 3](https://docs.djangoproject.com/ja/3.1/intro/tutorial03/)を進める。

関連記事のリンクは以下。
- [Djangoチュートリアル①（インストールとプロジェクトの作成）](https://qiita.com/honda28/items/34dceaeeb1cdddb4c9dd)
- [Djangoチュートリアル②（ビューの作成）](https://qiita.com/honda28/items/c91f78238ea3d53e776d)
- [Djangoチュートリアル④（テンプレート）](https://qiita.com/honda28/items/f62dc31e470ef3901706)
- [Djangoチュートリアル⑤（汎用ビュー）](https://qiita.com/honda28/items/7150a5df0213dc6a3927)
- [Djangoチュートリアル⑥（自動テスト）](https://qiita.com/honda28/items/f21fe43d29ffe7e15b5d)
- [Djangoチュートリアル⑦（静的ファイル）](https://qiita.com/honda28/items/bd0bfe8731a17609907c)