Django プロフェッショナル webプログラミング #1 -環境構築-

※以下の企画です

https://qiita.com/tatataichi/private/56936a028e625e62af8e

今回から「**Django プロフェッショナル webプログラミング**」をやっていきます！

https://books.mdn.co.jp/books/3220303045/

この書籍を選んだ理由は、いくつか見比べてみた結果、テンポとか図などの使い方が自分のフィーリングにマッチしていたからです。書籍は感覚で選ぶタイプ。センスに自信は無いけど。

社内向けのアプリを作るときは、Djangoフレームワークで簡易的なwebアプリをGCP環境でていきょうすることがほとんどなので、今までは必要な箇所をいろんな情報源から離散的に取得してなんとか作っていました。

それだとさすがにやばいと思ったので、しっかり体系的に勉強をしていきます。
**※自分が学びになったと思う部分をアウトプットするので、これからの記事が必ずしも体系的な内容になっているとは限りません。というか多分なりません**

# Part2①
いきなりPart2から始まるのは、Part1がPythonの書き方から始まるため。
これは今までの学習でなんとかなっているはずなのでサラッと目を通して終えた。
本題のDjangoの内容はPart2からなのでここから本格的に進めていく。

## DjangoのMTV
**MTVとはModel、Template、Viewの３つの重要な概念をまとめて呼称したもの**。
ここらへんの構成をしっかり意識できていない今の自分は、場当たり的な「**とりあえず動くもの**」を作ってしまいガチ。

しっかり以下の定義と役割を魂に刻み込む。
| 名称 | 役割 |
|:-:|:-:|
|  Model | データの処理方法を決めて、SQLを発行してDBとやりとりをする |
| Tmeplate |  HTML, CSS, JSでブラウザにどう表示するかを決める |
|  View |  リクエストをもとにモデル、テンプレートとのやりとりをして、受け取ったテンプレートとデータベースを組み合わせてレスポンスを返す |


SE Media様の解説画像を引用させていただくと以下のような概念図になる。
![引用1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/3461f58d-db6a-d71c-4eaf-7b6426484f33.jpeg)
> SE Media"Django 第2回 『MTVフレームワークのしくみを理解しよう』" 2024/5/10 
> https://se-media.jp/python/django/5044/

ブラウザからのリクエストを起点に、必要なデータをtemplateとmodelから集約してviewが返す。
それぞれの役割が重複しないように設計をしないと、なんか微妙に辻褄のあわないシステムになる。

## 開発環境
書籍場だとAWSのcloud9を用いられていたが、僕は現状GCP環境しかしっかり用意していないので、今回はcloud shell editorで代用する。
終盤で「デプロイしてみよう」みたいな内容になったときはいい感じにGCP環境に変換して触っていく（フラグの匂い…）

ここからはDjangoでプロジェクトを開始するための流れを学んでいく。

### プロジェクト立ち上げの流れ
おおよそ以下のような流れでプロジェクト作成する。

1. **プロジェクト作成**
1. **アプリケーション作成**
1. **マイグレート**

ちなみにプロジェクトとアプリケーションの言葉の説明は以下の通り。

| 名称 | 内容 |
|:-:|:-:|
|  プロジェクト | Webアプリ全体を管理するための設定や構成をまとめた単位|
|  アプリケーション |  特定の機能やロジックを実装したモジュール。プロジェクト内で独立した部品として扱うことができる |

プロジェクトでアプリ全体の共通設定、アプリケーションで実際に動作するものを作成するようなイメージ。それぞれディレクトリも分かれるので管理はそこまで困らないと思う。

ここからそれぞれざっくり方法をまとめる。

### プロジェクト作成
作業をしたいディレクトリで、以下のコマンドを打ち込む。
ローカルマシンだったらターミナルソフトで、Cloud9とかCloud shell エディタとかならCUIを起動して行う。

```Terminal:プロジェクト作成
django-admin startproject "プロジェクト名"
```

この書籍を読むまでは恥ずかしながら知らなかったのだが、「**プロジェクト名**」は、「**config**」にしておくと可読性が上がるのでおすすめらしい。
たしかに、「開発プロジェクト名」みたいな意味でこの名称を入れてしまうと、Djangoにおけるプロジェクトの意味は「**共通設定などを構成するもの**」なので、ややこしくなりそう。

実際、上記のコマンドを打ち込むと、設定した"プロジェクト名"のフォルダが作成されて、その配下に設定用のモジュールが作成されていくので、「**config > 設定用モジュール.py**」という構成になっている方が自然かも。

なので以下のようにする。

```Terminal:プロジェクト作成
django-admin startproject config .
```

※最後のドットは配置先のディレクトリを示していて、"."にすると現在のディレクトリに展開される。

### アプリケーション作成
同様にアプリケーションも作成していく。実際にviewの動作を記載していく部分になるので一番触れる時間が多いところかもしれない。

プロジェクト作成をした際に「manage.py」というモジュールが作成されているはずなので、そのディレクトリに移動して、以下のコマンドを実行。
アプリケーション名は特に推奨がある感じではなかったので、これこそ「開発プロジェクト名」とか「プロダクト名」とかをいれてもいいかも？

```Terminal:アプリケーション作成
python manage.py startapp "アプリケーション名"
```

今回は書籍の内容にならって「first_app」とした。
ここまでの作業で以下のようなディレクトリ構成になっているはず。

![スクリーンショット 2024-11-24 10.57.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/e2d825ff-bd81-13e0-e88c-44bc08cc89af.png)

### 開発用サーバーの立ち上げ
ここまでの操作で一応動くものにはなっているので、ちゃんと上手くいっているかの確認も込めてサーバーを立ち上げてみる。

cloud shellエディターだと以下のコマンドで立ち上げられる。
開発環境によってはIPアドレスの指定やポート番号の制限がある。

```terminal:開発用サーバーの立ち上げ
python manage.py runserver
```
※特に指定しなければ localhostの8000版ポートになるっぽい

すると以下のような結果が表示される。

```terminal:結果
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
November 24, 2024 - 01:59:27
Django version 5.1.1, using settings 'config.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```

上記に表示されている。
> http://127.0.0.1:8000/

というURL部分（いわゆるLocalhostアドレス）をコピペ（もしくは環境によってCtrl + click）してブラウザで確認し、以下画像のようなページが表示されれば一旦は成功。

![スクリーンショット 2024-11-24 11.07.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/3c7b892a-0697-fee9-e5e3-49250a5a7707.png)

## settings.pyの追記
続いては`settings.py`の編集を行う。
これはその人の状況によって異なると思うが、書籍にも記載があった以下は行っておいていいと思う。
また、`settings.py`では、言語設定やタイムゾーン、メディア用パスの設定などを行えるモジュールで、プロダクトフォルダの中にある（今回だと`config`フォルダ内）

1. 言語設定
1. タイムゾーン設定
1. アプリケーションの追記

それぞれ以下の通りで、「アプリケーションの追記」については、アプリケーションを追加するたびに記載が必要みたい。

```python:言語設定
LANGUAGE_CODE = 'ja'
```


```python:タイムゾーン設定
TIME_ZONE = 'Asia/Tokyo'
```


```python:アプリケーションの追記
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'first_app.apps.FirstAppConfig' #ここ
]
```

それぞれ記載を終えたら、再度`runserver`を実行し、以下のように日本語になっていればとりあえずOKっぽい。
![スクリーンショット 2024-11-24 13.36.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/b0364c05-fdff-81fd-6b44-649dc341cc1a.png)


## マイグレート
続いて行うのは**マイグレート**という作業。
正直言うと、一番なんとなくでやっている部分だ。

Djangoではモデル（`models.py`）にデータベースのスキームなどを記載し、モデルが変更する度にマイグレートファイルを生成する必要がある。これを**マイグレート**という。
これは実際にモデルを書いていくときに詳細な説明があるっぽいので一旦は、おまじない的に以下を行う。

```terminal:マイグレート
 python manage.py migrate
```

成功すると以下のようにわーっと結果が表示される。

```terminal:マイグレートの結果
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, 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 auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
```

ここまでできれば管理画面でデータの管理ができるようになる。
実際に入って見る前に管理画面にアクセスするためのアカウントを作成する。

```terminal:アカウント作成
python manage.py createsuperuser

ユーザー名 (leave blank to use '****_*****'): "アカウント名"
メールアドレス: "メールアドレス"
Password: "パスワード"
Password (again): "パスワード"
Superuser created successfully.
```
ユーザー名などは任意で設定して、忘れないようにする。本当によく忘れるので忘れないようにする…

最後に`runserver`を行い、Localhostアドレスに(これは実行している環境によってちょっと異なる)`/admin`というパスを設定してブラウザで開いてみると以下のようにアカウント認証画面となる。
ログインできれば管理画面に入れる。データベースを実際に運用しだすとどんなデータが登録されているかなどを管理画面上で確認することが出来るようになる。

![スクリーンショット 2024-11-24 13.55.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/cac82ca6-8606-c59c-124a-467dee52d7d4.png)

よしよし。あとはIDをとパスワードをいれて…

![スクリーンショット 2024-11-24 14.14.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/16167faf-22ef-af71-7918-d2407750e335.png)

**？！？！？！**

バージョンが古かったのか、書籍通りにやってもCSRF検証に失敗して入ることがログインすることができなかった。
色々調べてみたところ、以下の記事をみつけた。
`setteings.py`に`CSRF_TRUSTED_ORIGINS`なるものを設定しないとCSRF検証でエラーを起こすみたい。
ということで以下の記述（URL部分はマスクしている）を追加したところ…
```python:CSRF_TRUSTED_ORIGINS
CSRF_TRUSTED_ORIGINS = ['https://******']
```

![スクリーンショット 2024-11-24 14.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/2ad548b5-e8bf-9a15-dfb4-1640241a13b3.png)

いけた！！
**今回は終わり！！！**