Django 初心者が簡単なアプリをつくる2

2021/03/05 detail.htmlの覚え書きの間違いを訂正 @hama777 様 :bow_tone1: 

## はじめに
[Django 初心者が簡単なアプリをつくる1](https://qiita.com/soh506/items/4035650d2ea19e82d8fd)の続き。複雑なことや面倒なことを極力削ぎ落として、単純化したWebアプリを作り、Djangoの仕組みを学ぶことに特化する。バックエンド中心に何がどう繋がり動くのかだけを理解する。ひと通りCRUD(Create, Read, Update, Delete)を実装し、無事動けばゴール。（ネットに繋がないのにWebアプリ？というツッコミはナシでお願いします。）


### 初心者が簡単なアプリをつくるシリーズ目次
- [Django 初心者が簡単なアプリをつくる1](https://qiita.com/soh506/items/4035650d2ea19e82d8fd)
    - 準備・Djangoの全体像・models.pyの作成
- [Django 初心者が簡単なアプリをつくる2](https://qiita.com/soh506/items/98239c6b1c6fbf737429)(←今ココ)
    - Read部分の実装（urls.py・views.py・templateファイルの作成）
- [Django 初心者が簡単なアプリをつくる3](https://qiita.com/soh506/items/34cef1d386e1aa1b4496)
    - Create部分の実装（form.py等の作成)
- Django [初心者が簡単なアプリをつくる4](https://qiita.com/soh506/items/ac9b2914f64839edac3b)
    - Class-based-view と Function-view の比較
- Django [初心者が簡単なアプリをつくる5](https://qiita.com/soh506/items/fc6b00ba728ac41fa3d1)（完結）
    - Update部分・Delete部分の実装


### 環境
- Ubuntu 20.04 LTS
- Python 3.8.2
- Django 3.02

### 前提
プロジェクト名はconfig、アプリ名はmyapp とする。つまり以下2つのコマンド実行済み

- (myenv)$ django-admin startproject config .
- (myenv)$ python manage.py startapp myapp

templatesディレクトリはmanage.pyと同じ階層で、setting.pyも修正済み

## 1. urls.py をつくる
model.pyで情報が入った箱（もしくは表）ができたので、その情報をどこに貼り出すのかを決定する。そのためにまずconfig/urls.pyにコードを書く。
### config/urls.py のコード
```python:config/urls.py
from django.contrib import admin
from django.urls import path, include #includeを追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myapp/', include('myapp.urls')), #この行を追加
]
```
path(`'myapp/'`...の部分は、`127.0.0.1:8000/myapp/`の意味。includeカッコ内の`myapp.urls`は「myappディレクトリのurls.pyに詳しく書いてあるよ」という意味。
次にmyapp/urls.pyを作成。ファイルを自分で作成し編集する。まずは全体の一覧を表示する`index`（一覧画面）と、映画のタイトルをクリックしたらその映画の詳細が出る`movie_detail`（詳細画面）、この2つのアドレスのコードを書く。

### myapp/urls.py のコード
```python:myapp/urls.py
from django.urls import path
from . import views

app_name = 'myapp'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('movie/<int:pk>/', views.MovieDetailView.as_view(), name='movie_detail'),
]
```
### urls.py の覚え書き
コードの解説は以下の通り...ってただの覚え書き。
<img width="1317" alt="C569F59B-714E-403C-9E99-CF594A52FBDC.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321085/cf45066a-586f-e5c0-5d63-e4e27ad27271.jpeg">

初心者はどのコードが必要で、どこを変えていいのかあるいは変えちゃダメなのかがわからない。自分で勝手に決めていいのは

1. `''`とか`movie/<int:pk>`のアドレス部分
2. `IndexView`とか`MovieDetailView`の部分（あとからviews.pyに記述するから）
3. `index`とか`movie_detail`などのname=の後の部分

以上３つ。それ以外はDjangoやpythonに初めから備わっているコードや命令なので変えてはいけない。

### urls.py まとめ
path関数の中に以下の3つのコードを書く
1. アドレスを決定する
2. どのviewを使うかを決定する
3. アドレスをひとまとめにした名前をつける


## 2. views.py をつくる
models.pyで情報が入った箱をつくった。urls.pyでどこに貼り出すか（アドレス）を決めた。次にやるべきことは、modelに入っていた情報を「どう取り出し、貼る前の準備を整えるか」ということで、それを担うのがviews.py。

### Class Based View での実装
Viewを function（関数ビュー）にするか Class（クラスビュー）にするか、どちらがいいかと言えば。結論から言うとClass Based Viewのほうがオススメ。コードを書くのが非常に楽。ただ初心者にとっては、blackbox化して、何がどうなっているのかよくわからないため、どう使っていいのかわかりにくかったりする。本当はDocumentを読み込んで深く掘り下げていくとblackboxでもなんでもないことがわかるんだけど、説明している用語がさらにわからないのでチンプンカンプン。逆にview function はややコード量は多くなるもののどうやって動いているのかがよくわかる。今回はClass Based Viewで実装し、完了したら改めてview function で書き直すことを試みたい。つまりチュートリアルとは逆の順番で。先程は一覧画面と詳細画面のアドレスを決めたので、そこに表示するための情報の取り出しと情報を貼る準備のコードを書く。

### views.py のコード
```python:myapp/views.py

from django.views import generic
from myapp.models import Movie, Director, Log


class IndexView(generic.ListView):
    template_name = 'myapp/index.html'
    context_object_name = 'movie_list'
    queryset = Movie.objects.all()


class MovieDetailView(generic.DetailView):
    model = Movie
    template_name = 'myapp/detail.html'
```

これだけで完了。コードが素晴らしく少なくてすむ。あとは自動的にDetailViewが上手い具合に処理してくれる。覚え書きは以下の通り。

### views.py の覚え書き
<img width="1251" alt="79ED0F5D-22EC-4DD4-BF16-FD761F622640.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321085/e330ba28-ca0d-43c8-a8f6-13490f923f11.jpeg">

### views.py まとめ

【全体】
1. Class Based View を使うための generic をimportする
2. models.py で作った model (MovieとかDirectorとか)をimportする

【ListView】
3. queryset で model から情報を取り出し
4. その情報の固まりを context_object_name で名前をつけ
5. template_name で指定した HTML ファイルに情報を渡す

【DetailView】
6. 情報を持ってくるmodelを決定して
7. template_name で指定した HTML ファイルに情報を渡す


## 3. Template をつくる
ではいよいよちゃんと情報を表示させる段階。templateファイルとはHTMLファイルのこと。どのようにコードを書けばどう表示されるのか、を確かめる。その前にtemplatesディレクトリの中にmyappディレクトリを作成、そのmyappディレクトリの中でHTMLファイルを作成する。ディレクトリ構成は以下の通り。

```bash
.
├── config
├── db.sqlite3
├── manage.py
├── myapp
├── myenv
├── static
└── templates
    └── myapp #このディレクトリにHTMLファイルを作って入れる
        └── index.html
        └── detail.html
```

本来ならば、base.html を作り、{% block %} で拡張して...とやるんだろうが、もう愚直にindex.html と detail.htmlを作成する。

### index.html のコード
```html:templates/myapp/index.html
{% if movie_list %}
    {% for movie in movie_list %}
    <li>
        <a href="{% url 'myapp:movie_detail' movie.id %}">{{ movie.title }}</a>
        {{ movie.director }}
        {{ movie.watch_date }}
    </li>
    {% endfor %}
{% endif %}
```
で、runserverして表示を確認すると下図のようになる。

### index.html の結果(一覧画面)
![indexpicturecrop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321085/27f94377-e08e-4ba6-06dc-11fdf5c76f3a.png)

### index.html の覚え書き
<img width="1257" alt="0D505FE9-A3E7-4F95-98D7-6C23DD358983.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321085/ae1913f2-20c9-3fb6-c097-876ef5224747.jpeg">

一覧画面からタイトル部分のリンクをクリックすると詳細画面が表示されるが、そのコードは以下の通り

### detail.html のコード
```html:templates/myapp/detail.html
<h1>{{ movie.title }}</h1>
<h2>{{ movie.director }}</h2>
<h3>{{ movie.watch_date }}視聴</h3>

{% for log in movie.log.all %}
    <li>{{ log.text }}</li>
{% endfor %}
```
で、同じくrunserverで結果を表示してやると下図になる

### detail.html の結果(詳細画面)
![detailpicturecrop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321085/bae6004e-9b2f-bd76-ff60-13b1d2a81d8d.png)

### detail.html の覚え書き
★訂正箇所はここ↓
![Screenshot 2021-03-05 at 18.35.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321085/61d81a8e-c3b1-4aa7-bd32-a4189306329d.png)


### Template のまとめ
1. どこのファイルで書いた名前を引っ張ってくるか、をアタマに叩き込む
2. Django、Python、HTMLの3つカッコの使い分け、その合体技がtemplateになる
    - {{ 表示するための変数を書くときに使うカッコ }}
    - {% Pythonのコードを書くときに使うカッコ %} 
    - < HTMLのタグを書くときに使うカッコ >
3. 順参照なのか逆参照なのかの見極め大事。逆参照ならばrelated_nameを使う

## あとがき
どこがどう繋がっているのかさえ理解できれば、あとはその組み合わせでコードが書けたり、表示ができたりする。公式チュートリアルではその繋がりがわからなくて苦労した…。ちなみに公式チュートリアルの繋がりを初心者なりに理解してまとめたのが以下2記事(書いたのはワタクシ)

- [復習 Django チュートリアル ：views.py と urls.py はどうつながっているか](https://qiita.com/soh506/items/b2586ee07f63a74498e4)
- [復習 Django チュートリアル : view と 各html はどうつながっているか](https://qiita.com/soh506/items/699659a836df1eeab9f3)

1年半経っても亀の如き歩みで初心者の域を脱せず（泣）...ともあれ今回でCRUD(Create, Read, Update, Delete)のうちのRead部分ができたハズ。次回はCreate！の予定だが、浮気して関数Viewの書き直しに行くかもしれません。間違い等ありましたらご指導いただけるとありがたいです。