Django チュートリアル[その３]

[公式Djangoドキュメント　チュートリアル３](https://docs.djangoproject.com/ja/2.2/intro/tutorial03/)
#要約
##もっとビューを書いてみる
`path("[/polls/に続くURL]", viewsディレクトリの中の呼び出す関数名, 名前付け)`
`def detail(request, pathからの引数)`

```python
#polls/views.py
from django.http import HttpResponse

def index(request):
	return HttpResponse("Hello, world. You're at the polls index.")

def detail(request, question_id):
	return HttpResponse("You're looking at question %s. " % question_id)

def results(request, question_id):
	response = "You're looking as 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)
#------------------------------
#polls/urls.py
from django.urls import path
from . import views

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"),
]
```

`<int:question_id>`の部分はなんでも良いが、下記のように揃える。
`polls/detail/`に関する部分を`<int:question_idaaa>`に変更しても、正常に動作する。

```python
#polls/views.py
from django.http import HttpResponse

def index(request):
	return HttpResponse("Hello, world. You're at the polls index.")

def detail(request, question_idaaa):#変更
	return HttpResponse("You're looking at question %s. " % question_idaaa)#変更

def results(request, question_id):
	response = "You're looking as 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)
#------------------------------
#polls/urls.py
from django.urls import path
from . import views

urlpatterns = [
		path("", views.index, name = "index"),
		path("<int:question_idaaa>/", views.detail, name = "detail"),#変更
		path("<int:question_id>/results/", views.results, name = "results"),
		path("<int:question_id>/vote/", views.vote, name = "vote"),
]
```

##実際に動作するビューを書く
`render(request, テンプレート名, 辞書)`
テンプレートがない場合は、`HttpResponse`を使えばいい。（`render`はテンプレートの読み込みをショートカットできる）
`render`の引数に`context`を渡すことで、`index.html`側で`context(latest_question_list)`を受け取ることができる。

```python
#polls/views.py
from django.shortcuts import render
from .models import Question

def index(request):
	latest_question_list = Question.objects.order_by("-pub_date")[:5]
	context = {
		"latest_question_list": latest_question_list,
	}
	return render(request, "polls/index.html", context)
#------------------------------
#polls/templates/polls/index.html
{% if latest_question_list %}
	<ul>
	{% for question in latest_question_list %}
		<li><a href = "/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
	{% endfor %}
	</ul>
{% else %}
	<p>Mo polls are available.</p>
{% endif %}
```
つまり、`template = loader.get_template('polls/index.html')`を書かなくてよくなるということ。

##404エラー
`get_object_or_404(モデル名, 404を出したい時のキーワードを指定)`
404にならない時は、`question = Question.objects.get(pk=question_id)`と同等の扱いになる。

```python
#polls/views.py
from django.shortcuts import render, get_object_or_404

def detail(request, question_id):
	question = get_object_or_404(Question, pk = question_id)
	return render(request, "polls/detail.html", {"question": question})
```
##テンプレートシステムを使う
テンプレート側(`detail.html`)では`views`から渡された変数(`question`)に、`.`をつけて検索できる。

```python
#polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
	<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
#------------------------------
#polls/views.py
def detail(request, question_id):
	question = get_object_or_404(Question, pk = question_id)
	return render(request, "polls/detail.html", {"question": question})
```

##テンプレート内のハードコードされたURLを削除
`<a href="/polls/{{ question.id }}/">`を`<a href = "{% url 'detail' question.id %}">`に変更できる。
こうしておくことで、URLの変更は、`polls/urls.py`側だけで良くなる。

```python
#polls/urls.py
path("<int:question_id>/", views.detail, name = "detail"),
#------------------------------
#polls/templates/polls/index.html
<li><a href = "{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```
Djangoに複数アプリが存在する場合は、`app_name`を指定しておくといい。

```python
#polls/urls.py
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"),
]
#------------------------------
#polls/templates/polls/index.html
<li><a href = "{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
```