【Python】djangoのチュートリアルをやってみる<その2>

2019年2月3日

前回の続きでdjangoチュートリアルをやっていきたいと思います。

※一部チュートリアルとディレクトリ構成を変更している部分があります。

【Python】djangoのチュートリアルをやってみる<その1>

 

チュートリアルの続き

1.ビューを追加する

新たにビューを追加します。「polls/views.py」に以下のコードを追加します。

[highlight_python]

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)

[/highlight_python]

 

ビューとURLを紐づけます。「polls/urls.py」に以下のコードを追加します。

[highlight_python]

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’),
]

[/highlight_python]

そうしたら以下のURLにアクセスします。

http://127.0.0.1:8000/polls/1/

「You’re looking at question 1.」が表示されるはずです。(他にも追加していますが、割愛)

今回のビューはURLパラメータを使うパターンですね。urls.pyに“<型:変数名>”の形でパラメータを指定できるみたいですね。

 

2.さらにビューを追加する

Questionを最新で5つ表示するビューを追加します。

polls/views.py」のindexを編集し、以下のようにします。

[highlight_python]

from django.http import HttpResponse

from .models import Question

def index(request):
latest_question_list = Question.objects.order_by(‘-pub_date’)[:5]
output = ‘, ‘.join([q.question_text for q in latest_question_list])
return HttpResponse(output)

[/highlight_python]

ただし、ビューにハードコードで表示の出し分けロジックが書かれているので、こちらはテンプレートに出しましょう。

テンプレートを作成します。チュートリアル上では「polls/template」にindex.htmlを作成していますが、テンプレートはプロジェクト直下で一元管理できるようにしたいです。

プロジェクト直下にディレクトリを作成し、テンプレートを作成する

「manege.py」と同階層にtemplatesディレクトリを作成します。さらにそこにアプリケーション名のディレクトリを作成します(この場合はpolls)。そこに以下のようなindex.htmlを作成します。

[highlight_markup]

{% 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>No polls are available.</p>
{% endif %}

[/highlight_markup]

テンプレートの読み込む設定を変更する

デフォルトの設定では作成ディレクトリを読み込むことができないので、「settings.py」>「TEMPLATE」>「DIRS」を以下のように編集します。

[highlight_python]

TEMPLATES = [
{
“BACKEND”: “django.template.backends.django.DjangoTemplates”,
“DIRS”: [os.path.join(BASE_DIR, “templates”)],

# 以下省略

[/highlight_python]

ビューを修正する

次に「polls/views.py」にindex.htmlを読み込む処理を入れるため、indexを以下のように修正します。

[highlight_python]

from django.http import HttpResponse
from django.template import loader
from .models import Question

from . import APP_LABEL # この行を追加する

def index(request):
latest_question_list = Question.objects.order_by(‘-pub_date’)[:5]
template_name = “%s/index.html” % APP_LABEL
template = loader.get_template(template_name)
template = loader.get_template(‘polls/index.html’)
context = {
‘latest_question_list’: latest_question_list,
}
return HttpResponse(template.render(context, request))

[/highlight_python]

テンプレートを読み込む際はアプリケーション名を指定する必要があるのですが、毎回アプリケーション名を記載していくのはイケてないですよね。ですので、

[highlight_python]template_name = “%s/index.html” % APP_LABEL[/highlight_python]

アプリケーション内の変数としてAPP_LABELを定義することで、毎回アプリケーション名を指定する必要がないようにします。

アプリケーション内の変数を定義する

アプロケーション内の変数はアプリケーション下の「__init__.py」で定義します。この場合は「polls/__init__.py」を以下のようにします。

[highlight_python]

# -*- coding: utf-8 -*-
APP_LABEL = “polls”

[/highlight_python]

これで完了です。以下のURLにアクセスしたら正常に表示されるはずです。

http://127.0.0.1:8000/polls/

 

3.ビューでrender()を使う

ここからはチュートリアルに戻ります。

polls/views.py」のコードは多少省略できます。djangoにはrender()という関数が用意されており、こちらでHttpResponseなどの記載を省略できます。

render()を使用し、以下のように修正します。

[highlight_python]

from django.shortcuts import render
from .models import Question

from . import APP_LABEL

# Create your views here.
def index(request):
latest_question_list = Question.objects.order_by(“-pub_date”)[:5]
template_name = “%s/index.html” % APP_LABEL
context = {“latest_question_list”: latest_question_list}
return render(request, template_name, context)

[/highlight_python]

上記のコードでは元々インポートしていた以下はいらなくなったので削除しています。

[highlight_python]

from django.http import HttpResponse
from django.template import loader

[/highlight_python]

 

4.ビューで404エラーを表示する

チュートリアルでは冗長な書き方も試していますが、無駄なことはしません。

最初からショートカットを使って実装します。

polls/views.py」のdetailにQuestionがない場合404エラーを追加するように修正します。

[highlight_python]

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})

[/highlight_python]

上記のコードではdjangoが用意しているショートカット「get_object_or_404()」を使用しています。

簡単に動作確認のみをするならば、「polls/detail.html」を以下のようにします。

[highlight_python]{{ question }}[/highlight_python]

ここまでできたら、いったん以下のURLへアクセスし、出てきたQuestionを選んでみます。

http://127.0.0.1:8000/polls/

僕の場合は「What’s up?」を選択したら、「What’s up?」だけが表示されました。

今はテンプレートでquestion_textを表示しているのみなので、そうなりますよね。

 

テンプレートシステムを使う

ちゃんとした「polls/detail.html」を作ります。以下のようにします。

[highlight_python]

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

[/highlight_python]

 

ハードコードされているURLを削除

ハードコードは基本使いたいくないですよね。なので、ハードコードしないようにしましょう。

polls/index.html」を以下のように編集します。

[highlight_python]

<li><a href=”{% url ‘detail’ question.id %}”>{{ question.question_text }}</a></li>

[/highlight_python]

{  % url  %}を使用すると、「polls/url.py」で指定したname(第3引数に定義した値)によってURLを紐づけることができます。

 

URL名の名前空間

チュートリアルの表題そのままで何のことか分かりづらいですね。。。

多数のURLから対象を見つけ出す識別子をつけようという話です。アプリケーションの名前を定義します。

polls/url.py」を以下のように編集します。

[highlight_python]

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’),
]

[/highlight_python]

urlpatternsの上にapp_nameによって名前空間を設定します。

これによってpolls.detailによってURLを紐づけることができます。

名前空間を設定したので、「polls/index.html」を以下のように編集します。

[highlight_python]<li><a href=”{% url ‘polls:detail’ question.id %}”>{{ question.question_text }}</a></li>[/highlight_python]

これでOKです。