Djangoのチュートリアル 5 URLのハードコードを解消する
今回は、HTMLファイル内でリンクを張る際に、URLのハードコードを避けるプラクティスを紹介します。以下は前回までの記事です。
Djangoのチュートリアル 1 インストールから最初のビュー作成まで - pyhaya’s diary
Djangoのチュートリアル 2 モデルを作成する - pyhaya’s diary
Djangoのチュートリアル 2 モデルを作成する - pyhaya’s diary
目次
ハードコードとはどのような状態をいうのか
プログラミングにおいてコードが「ハードコード」された状態というのはDjnagoに限らず、嫌われる傾向があります。なぜか、それはコードが変更に弱くなるからです。一部を変更すると、ほかに何か所も同時に変更しなくてはいけない。ソースコードが巨大になるほどこれはミスを誘発しやすくなることは想像に難くありません。
今までのコードのどこがハードコードされているか?
ハードコードがいけないのはわかりました。では今まで書いてきたコードのどこが悪いでしょうか?以下のコードを見てみましょう。
polls/templates/polls/index.html
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
これはdetail.html
へのリンクを表しています。しかしurls.py
を見てみると、detail.html
のURLはviews.detail
に書かれていることがわかります。同じ場所へのリンクが2か所に分かれてしまっています。
するとこんなことが起きます。views.detail
のURLを何か理由があって別のものに変更しなくてはならなくなりました。この時、urls.py
のURLのみならず、HTMLファイルまで踏み込んで変更を反映させなくてはいけません。
これはソースコードが巨大になるほど大きな作業になることが想像できます。変更箇所は少ないほうがミスは少なくなります。
どう変更するか
DjangoにはURLのハードコードを避けるための仕組みがちゃんと備わっています。まず、現時点でのコードの状態を確認しておきます。
polls/templates/polls/index.html
<!DOCTYPE html> <html> <head> <meta charset='utf-8'> </head> <body> {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="/polls/{{ question.id }}/"> <!-- 問題の箇所--> {{ question.question_text }} </a></li> {% endfor %} {% else %} <p>No polls are available</p> {% endif %} </body> </html>
polls/views.py
from django.shortcuts import render from django.http import HttpResponse from .models import Question # 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): question = Question.objects.get(pk=question_id) return render(request, 'polls/detail.html', {'question' : question})
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'), ]
urls.py
のpath
の引数を見てください。name=...
という部分があります。これは今まで一切説明はしてきませんでした。これが実はハードコードを解消するために大きな役割を果たします。
ハードコードを解消したものが下になります。
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
最も特徴的なのが{% url %}
というタグを使っているところです。そのあとに'detail'という文がありますが、これはurls.py
のname
属性がdetailであるURLにリンクをつなげるということです。
urls.py
を見てみると、name='detail'
となっているのはviews.detail
をビューに指定しているURLです。このように、name='detail'
としているURLがあったので、question.id
をhref
に読み込みます。
このようなコードの書き方はURLの逆引きと呼ばれます(反対に、URLからビューを見つけるのを正引きと呼びます。)
これでハードコードは解消されました。このように変更してもページの表示のされ方は変わりません。
まとめ
今回は、{% url %}
テンプレートタグというものを用いてURLをハードコードしない方法を学びました。