【Django】settings.pyのINSTALLED_APPSとアプリケーション構成クラスとは？（3.2から推奨が変わった件も）

# 概要
* INSTALLED_APPSの記載方法について以下の2通りがありますが、django3.2から推奨の記載方法が変わっているらしいので備忘録。
    1. 明示的にアプリケーション構成クラスを書いて登録する場合
    2. アプリケーションパッケージ名を書いて登録する場合
* 上記の記載方法に付随するエラー（警告）2件についてメモ
    * primary keyを定義しておきない、という黄色の警告文
    * `INSTALLED_APPS`記載漏れによるRuntimeError


## 環境
* Mac
    * 機種ID：MacBookPro18,3
    * macOS：Monterey
    * チップ：Apple M1 Pro
    * メモリ：16GB
* Django version: 4.1.3

# `INSTALLED_APPS`とは
* djangoプロジェクトにアプリケーションを登録する（インストールする）際に必要になるのが、`INSTALLED_APPS`。
* ここにアプリケーション構成クラスを設定することで、アプリケーションでの編集がプロジェクトにも反映されるようになります。
* 例えば、mysiteプロジェクトでpollsアプリ作成時には以下がデフォルトで記載されています。

```mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```

# アプリケーション構成クラスとは
* `apps.py`にアプリケーション構成クラスが記載されています。
* 例えば、先ほどのpollsアプリケーションでは、以下のようにデフォルトで記載されています。

```polls/apps.py
from django.apps import AppConfig


class PollsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'polls'
```

# `INSTALLED_APPS`での登録方法は2通りある
* `INSTALLED_APPS`には2通りの登録の仕方があります。上記は「明示的に登録する」場合の記載方法ですが、「アプリケーションパッケージ名で登録する」場合の記載方法もあります。
* `apps.py`には、`name = 'polls'`と記載がありますよね。これをそのままパッケージとして追加することができます。先ほどのpollsアプリケーションの場合、以下のように登録してあげることができます。

```mysite/settings.py
INSTALLED_APPS = [
    'polls',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```

* 試しに、`'polls'`を`'aaaa'`にすると以下のようなエラーが出てきますので、`polls`だから読み込まれていることがわかりますね（もちろん、`'aaaa'`ではサーバーを起動しても「このサイトにアクセスできません」と表示されてしまいます）

```terminal
ModuleNotFoundError: No module named 'aaaa'
```

# `_init__.py`で`default_app_config`の設定は不要？
* INSTALLED_APPSで「アプリケーションパッケージ名を書く」場合の登録方法についてちょっと調べると、`_init__.py`をいじってあげる必要がある、という情報もありますが、実はdjango3.2以降（2021年4月6日リリース）で設定方法の推奨が変わったようです。
    * 参考：[Django最新バージョン3.2（LTS）がリリースされました](https://blog.pyq.jp/entry/pyq_news_0511)
* 3.2より前の場合、Djangoアプリの`__init__.py`で、変数`default_app_config`に`AppConfig`を設定する必要がありました。pollsアプリの場合は以下のようになるでしょう。

```polls/__init__.py
default_app_config = 'polls.apps.PollsConfig'
```

* ご自身が扱っているdjangoのversionを確認した上で、プログラムを触り始めるのがいいかもしれませんね。


# `'django.db.models.BigAutoField'`とは？
* 上に記載した`polls/apps.py`には、`default_auto_field = 'django.db.models.BigAutoField'`と記載がありますが、これもDjango 3.2からアプリケーション新規作成時点で設定されるもの。
* また、`settings.py`の一番下には以下がプロジェクト作成時点でデフォルトで記載されており、プロジェクト全体の主キーフィールドを指定しています。

```mysite/settings.py
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
```

*　プロジェクト全体ではなく、アプリケーションごとに主キーを指定する場合は、`apps.py`の`AppConfig`の`default_auto_field`属性を設定します。

```polls/apps.py
from django.apps import AppConfig


class PollsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField' # ここです
    name = 'polls'
```


# 3.2にアップデートしたら表示されるようになった黄色の警告文
* ただし、3.2から主キーの型をカスタマイズできるようになったことから、以下のような警告メッセージが黄色で表示されることがあります。

```terminal
 Auto-created primary key used when not defining a primary key type, by default ‘django.db.models.AutoField’.
```

* 自分もmigrate時にこの警告文に出会ったことがあります。djangoのバージョンを3.1以前から3.2にアップデートされた方は遭遇したことがあるかもしれません。
    * その場合は、`settings.py`に、今まで暗黙でデフォルトとなっていた`DEFAULT_AUTO_FIELD='django.db.models.AutoField'`を明示的に設定しておくと解決します。
    * 他にも方法はあるようなので、こちらご参照ください：[【django】警告文で「Auto-created primary key used when not defining a primary key type, by default ‘django.db.models.AutoField’.」の対応策](https://freeheroblog.com/django-auto-created-pk/)
    
* 3.2変更時の公式サイトはこちら：[Customizing type of auto-created primary keys¶](https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys)


# `INSTALLED_APPS`に登録していないと、migrate時にエラーが発生
* モデルを定義しているのに、`INSTALLED_APPS`にアプリケーションを登録していないと、マイグレート時やrunserver時に以下のエラーが発生します。
* pollsアプリのQuestionモデルの場合は以下のエラーメッセージです。

```terminal
RuntimeError: Model class polls.models.Question doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
```

* このエラーに遭遇した場合は、`INSTALL_APPS`で対象のモデルを含むアプリが登録されているかどうか確認しましょう。