[Django]コマンドと役割を整理する

# プロジェクトの作成
```python:command
django-admin startproject {プロジェクト名}
```
# アプリケーションの作成
manage.pyのあるディレクトリで以下のコマンド

```python:command
python manage.py startapp {アプリ名}
```

## url用のディレクトリを作成

```python:{アプリ名}/urls.py
from django.urls import path

from . import views

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

## {プロジェクト名}/urls.py
こちらの`urlpatterns`には各アプリケーションからのURLConfを書く

```python:{プロジェクト名}/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]
```

# 各種設定
## タイムゾーンと言語コード
```python:{プロジェクト名}/settiong.py
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
```

## データベースの作成
`migrate`コマンド...ファイルのデータベース設定に従って必要なすべてのデータベースのテーブルを作成する

```python:command
python manage.py migrate
```


# モデルを反映させる
```python:command
python manage.py makemigrations {アプリケーション名}
```
`makemigrations`を実行することで、Djangoのモデルに変更があったことを伝えそして変更を反映する形で保存することができる。

# Django Adminについて
Django Adminは管理者だけが入ることができるWebサイトの情報をブラウザから編集できるページです。
管理者だけが入れるadminサイトには管理ユーザを作成することでアクセスすることができます。

```python:command
python  python manage.py createsuperuser
```

## 管理サーバの起動
管理サーバの起動には`python manage.py runserver`でサーバを起動します。
そのあとローカルドメインの"/admin/"つまりは[http://127.0.0.1:8000/admin/](http://127.0.0.1:8000/admin/)にアクセスします。
アクセスすると下記のような画面が表示され管理ユーザで作成した`Username`と`Password`を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472955/bfe10836-7880-2b2b-819a-5129078ec6f5.png)

## アプリをadmin上で編集できるようにする
アプリをadmin上で編集できるようにするには`{アプリ名}/admin.py`を編集します。
例えばQuestionオブジェクトがadminインターフェースを持つということをadminに伝える場合は以下のように書きます。

```python:{アプリ名}/admin.py
from django.contrib import admin

from .models import Question

admin.site.register(Question)
```

# オーバービュー
## ビューとは
Djangoのアプリケーションにおいて特定の機能を提供するウェブページの「型(type)」です。
ブログアプリケーションだと以下のようなビューがあるはずです。

- Blog ホームページ - 最新エントリーをいくつか表示
- エントリー詳細ページ - 1エントリーへのパーマリンク (permalink) ページ
- 年ごとのアーカイブページ - 指定された年のエントリーの月を全て表示
- 月ごとのアーカイブページ - 指定された月のエントリーの日をすべて表示
- 日ごとのアーカイブページ - 指定された日の全てのエントリーを表示
- コメント投稿 - エントリーに対するコメントの投稿を受付

## Djangoにおけるビュー
Djangoではウェブページとコンテンツはビューによって提供されます。
各ビューは単純にPython関数として実装されています。

またDjangoではビューをリクエストされたURLから決定します。
URLからビューを得るには、Djangoは「URLconf」を使います。

```python:{アプリ名}/urls.py
from django.http import HttpResponse

def index(request):
    return("Hello,world.You`re at athe polls index.")

# Create your views here.
def detail(request, question_id):
    return HttpResponse("You`re looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You`re voting on question %s" % question_id)
```

このようにviewsを作ったとします。

これらのviewを{アプリ名}/urlsモジュールと結び付けます。

```python:アプリ名/urls.py
from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

path(URLパターン,実行メソッド, nameタグ)の順で書きます。
これらはrootのurlから探索していきます。
こちらですね。

```python:{プロジェクト名}/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

```
`requstが来るとDjangoでは{プロジェクト名}/urls.pyのurlpatterns変数を探索　⇒ pathのパターンマッチ⇒urlpatterns変数を探索⇒pathのパターンマッチ`
という形でメソッドを実行します。

## 具体的に動作するビュー
各ビューには以下の二つの役割があります。
- ページのコンテンツを含むHttpResponseオブジェクトを返す
- Http404のような例外の送出

これら以外の処理はユーザ次第になります。

`DjangoにとってはHttpResponseがあるか例外かだけです。`

## プロジェクトのテンプレート
{プロジェクト名}/setting.pyにはDjangoがどのようにテンプレートをロートして表示内容を整形する(レンダリング)するかがかかれています。
デフォルトの設定ファイルでは、DjnagoTemplatesバックエンドが設定されています。
そのAPP_DIRSがTRUEになっているとDjangoTemplatesはINSTALLED_APPSのそれぞれの"templates"サブディレクトリを検索するようになっています。

作成したアプリディレクトリでtemplatesというディレクトリを作成します。
次にtemplatesディレクトリを作成内で`同じアプリ名`のディレクトリを作成し、さらにその中にindex.htmlというファイルを作成します。

公式のチュートリアルにあるようにアプリ名を`polls`とした場合は以下のようなディレクトリ構造になります。

```
polls/
└ templates/
　 └ polls/
　 　 └ index.html
```

これには以下の理由があります。

Djangoは名前がマッチした最初のテンプレートを使用する。
もし異なるアプリケーションの中に同じ名前のテンプレートがあった場合はDjnagoのはそれらを区別することができない。正しいテンプレートを取得する一番簡単な方法はそれらに名前空間を与えることである。

templateをビューに反映させる場合は以下のように記述します。

```polls/views.py
from django.http import HttpResponse
from django.template import loader

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html') # templateをロード
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request)) # コンテキストを渡す
```

### ショートカット:render()
いちいちloaderやHttpResponseをimportするのってめんどくさいですよね。
そのようなあなたにはrenderメソッドおすすめです。
`from django.shortcuts import render`
とするだけでloaderもHttpResponseも使うことができます。

## ショートカット:get_object_or_404()
get()を実行しオブジェクトが存在しない場合にHttp404を送出することは非常によく使われるやり方です。

```
from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})
```

この`get_object_or_404'は

```
try:
    question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
    raise Http404("Qeustion does not exit")
```
を省略した形になります。

## URL間の名前空間
例えばpollsアプリはdetailビューを含むが、同じプロジェクトにブログのためにアプリがあり、そのアプリも同名のビューを含むかもしれないときに{% url %}テンプレートタブを
使ったときにdjangoはどのアプリのビューに対してurlを作成すればよいのだろうか？
Djnagoにそれを知らせるためにはURLconfに名前空間を追加することでできる。

{アプリ名}/urls.pyファイル内でapp_nameを追加してアプリケーションの名前空間を設定する。

```python:{アプリ名}/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/results/', views.results, name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

## ListViewとDetailView

```python:{アプリ名}/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from .models import Choice, Question


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'


class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'


def vote(request, question_id):
    ... # same as above, no changes needed.
```


ListViewは「オブジェクトのリストを表示する」および「あるタイプのオブジェクトの詳細ページを表示する」という二つの概念を抽象化するために使用します。

- 各汎用ビューは自分がどのモデルに対して動作するのかを知っておく必要がある。こではmodel属性を使用して提供される。
- DetailView汎用ビューには"pk"という名前でURLからプライマリーをキャプチャして渡すことになっている。

### DetailView
デフォルトではDetailView汎用ビューは<app name>/<model name>_detail.htmlという名前のテンプレートを使用する。
temple_name属性を使用すると自動生成されたデフォルトのテンプレート名ではなく、指定したテンプレート名を使うようにDjangoに伝えることができる。

### ListView
ListView汎用ビューは<app name>/<model name>_list.htmlというデフォルトのテンプレートを使うので、template_nameを使ってListViewに既存の"polls/index.html"テンプレートを使用するように伝えます。


# 参考
- [はじめての Django アプリ作成、その 1 \| Django ドキュメント \| Django](https://docs.djangoproject.com/ja/3.0/intro/tutorial01/)
- [はじめての Django アプリ作成、その2 \| Django ドキュメント \| Django](https://docs.djangoproject.com/ja/3.0/intro/tutorial02/)
- [はじめての Django アプリ作成、その 3 \| Django ドキュメント \| Django](https://docs.djangoproject.com/ja/3.0/intro/tutorial03/)
- [はじめての Django アプリ作成、その 4 \| Django ドキュメント \| Django](https://docs.djangoproject.com/ja/3.1/intro/tutorial04/)