前回
に引き続き、こちらのサイトのサンプルを試していきます。
はじめての Django アプリ作成、その 3 | Django documentation | Django
pollsディレクトリ内にtemplatesディレクトリを生成します。
そうするとそこからDjangoが各アプリのテンプレートを探してくれるようです。
raspberrypi:~/dreamer $ mkdir polls/templates
さらにpollsというディレクトリを作り、index.htmlというファイルを作ります。
raspberrypi:~/dreamer $ mkdir polls/templates/polls
raspberrypi:~/dreamer $ nano polls/templates/polls/index.html
何層ものディレクトリだけどDjango内では「polls/index.html」として扱われるそうです。
templatesの中に直接index.htmlを置くとDjangoが混乱するのか、使う人が混乱するのかは今の所わからないけど、どのアプリのindex.htmlの話なのか解りにくくなるそうなのでtemplatesディレクトリ内にもう一度アプリ名のディレクトリを作るのが良いそうです。
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>No polls are available.</p>
{% endif %}
polls/views.pyも指定通りに編集します。
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))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)
サーバー起動!
raspberrypi:~/dreamer $ python3 manage.py runserver 0:8000
あれあれ?エラー?
しかしそこはpythonさん、ちゃんと理由を教えてくれます。ターミナルでも同じメッセージが出ています。
Questionの名前がみつかりません。
はい、ゴメンナサイ。書いていませんでした。。
書いたよー!もっかい!
あれあれれ?
今度はloaderが見つからないぞと
ゴメンナサイゴメンナサイ!pythonさん!
renderとloaderを見間違えてたなんて。。
もっかいチャンスをください!!
3度目の正直!
ヨッシャァァアアアーーーー!!!
やっと通ったぁあああ!!!
polls/views.pyのindex関数部分
def index(request):
#latest_question_listにSQLiteから引き出したquestionをリスト化して格納
latest_question_list = Question.objects.order_by('-pub_date')[:5]##polls/templates/poolls/index.htmlをテンプレートとして呼び出して
template = loader.get_template('polls/index.html')#コンテキストにリストを辞書方式で格納して
context = {
'latest_question_list': latest_question_list,
}#テンプレートをコンテキストでレンダリングして値を返す
return HttpResponse(template.render(context, request))
という流れですね。(違ってたら教えてください。)
で、この中の「ロードしてコンテキストに格納して値を返す」という一連の流れがよく使われるからrender()関数としてまとめられている。ということで
先ほどのはコメントアウトして、
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
from .models import Question
# Create your views here.
'''
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
'''
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)
試してみましょう。
raspberrypi:~/dreamer $ python3 manage.py runserver 0:8000
ちゃんと動いた。へー!便利なんですねー
renderは第一引数にリクエスト値、第二引数にテンプレート、第三引数にコンテキストを適用させるようです。
ここからは、面倒くさいエラー処理に関する事項です。
値の無いアドレスを読み出すと404エラー表示するというものです。面倒ですが理解するため頑張ります。
raspberrypi:~/dreamer nano polls/views.py
を
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
from .models import Question
from django.http import Http404
# Create your views here.
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)def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
と編集して
detail用のテンプレートを生成
raspberrypi:~/dreamer nano polls/templates/polls/detail.html
中身は
{{ question }}
だけ。
実行すると、questionのあるものは値が表示され、
無いものは404エラーで下にraise Http404("Question does not exist")で渡した値が表示されています。
でこの404エラーもショートカット関数が利用できるのですね。
from django.http import HttpResponse
from django.template import loader
from .models import Question
from django.http import Http404
from django.shortcuts import get_object_or_404, render
# Create your views here.
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)
'''
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
'''
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
試してみると、先ほどとメッセージが違います。これが自動生成されたメッセージなんですね。
次にdetal.htmlの中身を弄ってquestion内容が表示されるようにします。
raspberrypi:~/dreamer nano 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>
で、forループ内でpythonのquestion.choice_set.all()を呼んでいるそうです。(よくわからん)
その結果、polls/(値)を入れるとをの中身が見えます。
なんと、値は全角でも大丈夫なようです
無い値を入れると当然404エラーが返ります。(viewsは弄ってないですから当然ですね)
次に{%url%}を利用してテンプレート内のハードコートされたコードに依存性を無くすという方法があるようですので試してみます。
raspberrypi:~/dreamer $ nano 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>-->
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
urls.pyを書き換えます
raspberrypi:~/dreamer $ nano polls/urls.py
を
# path('<int:question_id>/', views.detail, name='detail'),
path('test/<int:question_id>/', views.detail, name='detail'),
引数の前のURLに好きな名前を付けると
おー、アドレスがdetailではなく、testとなっています。
で、これが何が便利かといいますと・・・・・・・わかりません!
僕の今のレベルではよくわかりませんが、きっと使いこなせると便利なことに気が付くのでしょう!
で、この方法をすると、「じゃあ他のアプリ使ったときに名前がかぶらね?」となるってことらしいのですよ。うん、なりそうですね。
その解決方法にurls.pyにapp_nameという名前を設定するそうです。
どれどれ?
raspberrypi:~/dreamenano polls/urls.py
を変更といっても1カ所だけ
from django.urls import path
from . import views
app_name = 'polls' #←ここだけ
urlpatterns = [
path('', views.index, name='index'),
# ex: /polls/5/
# path('<int:question_id>/', views.detail, name='detail'),
path('test/<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'),
]
うん、この状態でそのままアクセスするとどうなるか試したみたら
怒られた。そりゃそうか
raspberrypi:~/dreamer $ nano 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>-->
<!--<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>-->
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
実行すると、あれ?やっぱ怒られた?
ずずーと下を見ると「ここがおかしいですよー」とDjangoさんが教えてくれてます。
え?これってセキュリティー的には大丈夫なの?
ともかく、<!---->でコメントアウト出来てると思っていたものが出来ていなかったということですね。テンプレートのコメントアウトはHTML方式ではないのかな?
とりあえず、コメントアウトした行を消し去るとちゃんと見えました。
結構謎な部分を残しながらですが、ひとまずテンプレートってこんな感じで柔軟性のあるコードも書けるんですよー。てことをやんわりと勉強しました。
次回はフォームの書き方
はじめての Django アプリ作成、その 4 | Django documentation | Django
を参考に奮闘します。