dockerでmysqlコンテナ作ってdjangoから接続する

# この記事でやること
dockerでmysqlのコンテナを作ってdjangoのDBをデフォルトのSQliteからmysqlにする。

状況がよくありそうで探せば色々先人の記事がありそうですが、自分でやっていて結局色々な記事を横断して環境構築したので、自分の備忘録のためにも記事にしておきたいと思います。

後ろの参考文献にも書いておきますが、
[[ Docker compose] Django+React 環境構築
](https://zenn.dev/maha17/articles/ade5fc1dbc9d02)
でDjangoとReactの環境を作った後にMySQLにDjangoで使うDBを変更したいなと思ってこの作業をしたので、上のリンクでの設定を前提としてこの記事を書いています。

なので、前段階としてDjangoのプロジェクト作成あたりの設定はしてある体で書いています。

### 環境
docker  : 25.0.3
django : 3.2.25


# 作業手順

## 1\.必要なライブラリのインストール
MySQLを利用するのにpymysqlを使います。あとで入れ忘れたりとかがめんどいので、先にrequirements.txtに入れておきます。


```python:requirements.txt
Django<4
djangorestframework>=3.11.0,<3.12.0
django-cors-headers==3.2.1
pymysql
```

## 2\.下準備
dockerコンテナ起動時にまとめてMySQLのコンテナも起動させたいので、docker-compose.ymlにMySQLの設定を入れます。

### MySQLコンテナのDockerfile記述
その前に下準備として以下の手順でDB関連の設定をしていきます。

```sh
mkdir -p db_MySQL/db
mkdir -p db_MySQL/docker
touch db_MySQL/docker/Dockerfile
```

ここまででdb_MySQL/docker/の配下にDockerfileができたので設定を書き込みます。docker起動時にmysqldが実行されるようにしておきます。
```dockerfile
FROM mysql
EXPOSE 3306

CMD ["mysqld"]
```

確認のため、出来上がりのディレクトリ構成はこんな感じ。
```
./db_MySQL
├── db
└── docker
    └── db
        └── Dockerfile
```

### docker-compose.ymlの設定
```docker
  mysql:
    build: 
      context: ./db_Mysql
      dockerfile: docker/db/Dockerfile
    volumes:
      - ./db_Mysql/db:/db
    image: original_mysql_world
    env_file: env/db_env
```

ここでmysqlのユーザ名とパスワードはenvファイルを別に作って管理してます。

https://qiita.com/atom00/items/a12c994ad18ea7afc43c

前にここについては記事にしてるので簡単に書くと、env/db_envのファイルを作ってそちらでpasswordなどの設定を記載しています。

### Djangoの設定

1.manage.pyの設定
```python:manage.py
# 下を追記
import pymysql
pymysql.install_as_MySQLdb()
```

```python:settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysql',
        'USER': '<ユーザ設定>',
        'PASSWORD': '<パスワード設定>',
        'HOST': 'mysql',
        'PORT': '3306',
    }
}
```
settings.pyについてはそのまま載せるのに問題があるので、os.environ.get()で設定するか、別にlocal_settings.pyなど適当に作成してimportする方法があります。

例えば下のような感じ。

```python:settings.py
try:
    from .local_settings import *
except ImportError:
    pass
```

```python:local_settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysql',
        'USER': '<ユーザ設定>',
        'PASSWORD': '<パスワード設定>',
        'HOST': 'mysql',
        'PORT': '3306',
    }
}
```
## 3\.接続の確認
### 起動の確認
dockerコンテナを再起動して、MySQLのコンテナを起動します。

```
docker-compose down && docker-compose build --no-cache && docker-compose up -d
```

docker desktopの方で起動が確認できたらOK.

### モデルの定義
トピック的に接続の確認のためにするというか、Djangoまわりの設定をしている過程でする作業ですが。

models.pyにモデルを設定しておきます。
mysqlとの接続とは直接関係しない部分なので割愛。

### モデルが反映されたか確認
```sh
docker-compose run backend sh -c "python manage.py makemigrations <プロジェクト名>"
docker-compose run backend sh -c "python manage.py migrate <プロジェクト名>"
```

```
docker-compose exec db mysql -u <ユーザ名> -p <データベース名> -e "SHOW TABLES;"
```

これを実行するとパスワード入力が求められるので、入力する。
うまく行っていればデータベースにテーブルが作成されていて、モデルで設定した名前が表示されます。

# 詰まった点
作業途中でPCのOSのアプデをしたら再起動したときにdjangoのローカルサーバーに繋がらなくなった。


データベースを入れているコンテナの起動タイミングとdjangoの入っているコンテナの起動タイミングの問題で正しく接続がされなかったから。
DBの方を再起動したら直った。

# 参考文献
- [[ Docker compose] Django+React 環境構築
](https://zenn.dev/maha17/articles/ade5fc1dbc9d02)
- [[ Docker compose] Django+React Todoアプリ作成①](https://zenn.dev/maha17/articles/dad37f4e36656a#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E5%AE%9A%E7%BE%A9)
- [DjangoでMySQLに接続(Docekrコンテナ別)](https://qiita.com/Tett/items/5def7bbcd981bbdcd784)