【Django】001. (Djangoでの) Webページの基本

前回はDjangoでロケットを飛ばすまでを見ていきました。
[前回記事：【Django】000. Hello World (ロケット飛ばすまで)](https://qiita.com/ys_dirard/items/82d12c772494fd8a324b)

今回はDjangoということを念頭に置いてWebページの基本について確認していきます。

今回からしばらくは以下の本で学習をしていきたいと思います。

https://www.shuwasystem.co.jp/book/9784798062419.html

### MTVって何？
MTVとは以下の要素で構成されています：
* Model
    * データベースの設計
    * データベースとのやり取り
* Templates
    * requestで返すHTMLファイル (ファイル自体は枠みたいなものであり、求められている要素を埋め込んで返すイメージ)
* View
    * 様々な処理を行う
    * ユーザーに返すTemplateファイルを決定する
    * データをTemplateに渡す

![https://djangobrothers.s3.amazonaws.com/image_content/fe8731fefac0447eaf8649fe47c48e9a/MVT2.png](https://djangobrothers.s3.amazonaws.com/image_content/fe8731fefac0447eaf8649fe47c48e9a/MVT2.png)

https://djangobrothers.com/tutorials/memo_app/mtv/

## プロジェクトとアプリケーション
DjangoでのアプリケーションはMTVの処理をひとまとめにしたものと考えられます。

1つのプロジェクト内で機能ごとに複数のアプリケーションを分けて作成するのが一般的のようです。
※まぁ分けた方が管理しやすいことは想像できますね。

![https://djangobrothers.s3.amazonaws.com/952ccd49-1f48-4780-b58c-4d3da843a262.jpg](https://djangobrothers.s3.amazonaws.com/952ccd49-1f48-4780-b58c-4d3da843a262.jpg)

https://djangobrothers.com/tutorials/memo_app/mtv/

## アプリケーションの作成
```sh
python manage.py startapp アプリケーション名
```
```hello```という名前のアプリケーションを作成する場合は以下となる。
```sh
python manage.py startapp hello
```

## アプリケーションの中身
以下のhelloフォルダが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/f8756c41-5afa-ebc9-926b-9b316c28a304.png)

### views.pyにページ表示を書く
```hello/views.py```は生成時以下のようになっている：
```python
from django.shortcuts import render

# Create your views here.

```

以下のように書き換える：
```python
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello Django!!")

```

HttpResponseを返すindex関数を定義しました。
※ただ単に「Hello Django!!」という文字列を返すだけのもの。

## urls.pyについて
### 現在の問題点
views.pyの変更でユーザーに返すHttpResponseは定義しましたが、ユーザーからのRequestを受け取った後どうすればよいかを定義していません。

すなわちユーザーからRequestを受け取ったら、views.pyのindex関数によってRequestを返してくださいね！という指示が必要ということです。

### urls.pyを書き換える
プロジェクトのurls.pyはデフォルトで以下のようになっています：

```python
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path("admin/", admin.site.urls),
]

```

ここに以下のようにhelloへのルーティングを追加します：

```python
from django.contrib import admin
from django.urls import path
import hello.views as hello # 追加

urlpatterns = [
    path("admin/", admin.site.urls),
    path("hello/", hello.index) # 追加
]

```

これによりサーバーを起動し、いかにアクセスするとhello/viewsのindex関数が動作していることが確認できる。
```http://127.0.0.1:8000/hello/```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/2cde195c-0bdd-670a-fd27-6a9b3546cc31.png)

### アプリケーションごとにurls.pyを作成する
先ほどの方法はプロジェクトのurls.pyにルーティングを累加しましたが、アプリケーションごとにルーティングを管理するのが一般的です。

以下のように変更していきます。

まずhelloフォルダ内にurls.pyを以下の内容で作成する。
```python
from django.urls import path
from . import views

urlpatterns = [
    path("", views.index, name="index"),
]

```
次にプロジェクトのurls.pyを以下に変更する。
```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("hello/", include("hello.urls")),
]

```

hello.indexからhello.urlsに変更し、hello.urlsに飛んだ後index関数を指定するような構成になっています。

この方法により、アプリケーション側にurlを追加する場合はhello/urls.pyを編集、プロジェクトにアプリケーションを追加する場合はプロジェクトのurls.pyにアプリケーションのurlを追加という構成になりました。

## クエリパラメータ
クエリパラメータは次のようにアドレスの後に続けて記述するパラメータ：
```http://ドメイン?key=value&key=value&...```
```?```以降のkey, valueがパラメータです。

### クエリパラメータの表示
hello/views.pyのindex関数を以下に変更します：

```python
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    msg = request.GET["msg"]
    return HttpResponse(f"you typed: {msg}.")

```

サーバーを起動し、以下にアクセスすると画像のような結果になります。
```http://127.0.0.1:8000/hello/?msg=hello```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/d7633d14-7518-c1cb-cf0a-8b24c1880cfb.png)

### パラメータがないときは？
以下のようにエラーとなる：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/f444864a-a34c-f896-af0d-fbe7180ddc47.png)

### パラメータがないときのエラーハンドリング
hello/views.pyのindex関数を修正する：

```python
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    if "msg" in request.GET:
        msg = request.GET["msg"]
        result = HttpResponse(f"you typed: {msg}.")
    else:
        result = "please send msg parameter!"
    return HttpResponse(result)

```
そのまんまですね。

### クエリパラメータではなくパスを指定して送る方法
```http://domain/?id=123&name=taro```
ではなく、
```http://domain/123/taro```
のように送るという話。

#### urlpatternsを修正する
hello/urls.pyのurlpatternsを以下に修正：
```python
from django.urls import path
from . import views

urlpatterns = [
    # path("", views.index, name="index"),
    path("<int:id><name>", views.index, name="index"),
]

```

#### index関数を修正する
hello/views.pyのindex関数を以下に修正：
```python
from django.shortcuts import render
from django.http import HttpResponse

def index(request, id, name):
    result = f"your id: {id}, name: {name}."
    return HttpResponse(result)

```

以下にアクセスすると画像の結果になります。
```http://127.0.0.1:8000/hello/123/taro/```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/88dffeca-f73a-8695-b478-463e07d90abc.png)

index関数の引数のidにurlの123が、nameにurlのtaroが渡されていることがわかります。

#### 【参考】urlpatternsはいろいろできる
以下のようにurlpatternsに記載することもできる：
```python
urlpatterns = [
    # path("", views.index, name="index"),
    path("<int:id>/<name>/", views.index, name="index"),
    path("my_name_is_<name>.I_am_<int:id>_years_old.", views.index, name="index"),
]
```

この場合は例として以下でアクセスできます。
```http://127.0.0.1:8000/hello/my_name_is_taro.I_am_22_years_old.```

## まとめ
今回はDjangoにおけるWebページ作成の基本 (思想とルーティング周り) を見ていきました。

慣れるまで大変そうですが続きも楽しんでいきたいです。