Django公式のチュートリアル「Writing your first Django app, part 3」を元に進んでいきます。
チュートリアル – その3では、以下の内容を学びます。
- データの型について
- 実用的なviewの書き方
- htmlファイルを作る場所
- if文とfor文
- urlの書き方
- リレーションシップについて少し
app1 $ source myenv/bin/activate
(myenv) app1 $ cd mysite
(myenv) mysite $
一般的なサイト
ブログサイトを例にサイトの基本的な構造を見てみましょう。
- サイトのトップページ(ホームページ)
- 記事の一覧ページ
- 記事のページ
- カテゴリーページ
- etc…
こんな構造になっていて、それぞれにURLが付与されています。
pollsアプリでは、以下の4つのviewを作成していきます。
- トップページ(質問をいくつか表示)
- 質問の詳細ページ(結果は表示しない)
- 質問の結果ページ(特定の質問の結果を表示)
- 投票ページ(特定の質問の選択を投票するページ)
viewを書いてみる
polls/views.pyに以下の内容を追加・保存してください。今回の関数には引数を設定しています。
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
# ここから下を新しく追加
# detailは詳細という意味
def detail(request, id):
return HttpResponse("detailページは質問 %s の詳細を表示します。" % id)
# resultsは結果という意味
def results(request, id):
response = "resultsページは質問 %s の結果を表示しています。"
return HttpResponse(response % id)
# voteは投票という意味
def vote(request, id):
return HttpResponse("voteページは質問 %s に投票します。" % id)
以前書いた、index関数と違う点が2つがあります。
- 引数の(request)が、(request, id)になっている
- HttpResponseが(“文字列 %s.” % id)になっている
関数の引数にidを設定することで、URLからidを受け取り、関数内でidを変数として使えるようなります。
「”文字列 %s.” % id」の部分は、%sの場所に、%の後のidを入れて下さい。といコードです。
この書き方は分かりにくさがあるので、最近はfストリングスという記法が使われたりします。
以下の2つは同じ結果になります。
>>> id = 20
>>> "detailページは質問 %s の詳細を表示します。" % id
detailページは質問 20 の詳細を表示します。
# fストリングス
>>> f"detailページは質問{ id }の詳細を表示します。"
detailページは質問 20 の詳細を表示します。
「f”文字列 { 変数 }”」と書くことで、どこに何の変数を入れているか一目で分かるようになります。
次に、urlからviewに「id」を渡すため、urls.pyを設定していきます。
polls/urls.pyに以下の内容を追加して下さい。メモは削除してもらっても構いません。
from django.urls import path
from . import views
app_name = 'polls' # アプリ名を設定
urlpatterns = [
path('', views.index, name='index'),
# detail関数を呼び出すurl
path('<int:id>/', views.detail, name='detail'),
# results関数を呼び出すurl
path('<int:id>/results/', views.results, name='results'),
# vote関数を呼び出すurl
path('<int:id>/vote/', views.vote, name='vote'),
]
ここにもidが出てきましたね!
- detailのurl
「http://127.0.0.1:8000/polls/1」にアクセスすると、idが1としてdetail関数に渡される - resultsのurl
「http://127.0.0.1:8000/polls/1/results/」にアクセスすると、idが1としてresults関数に渡される - voteのurl
「http://127.0.0.1:8000/polls/1/vote/」にアクセスすると、idが1としてvote関数に渡される
「http://127.0.0.1:8000/polls/好きな数字」にアクセスしてみて下さい。
「detailページは質問好きな数字の詳細を表示します。」が表示されたと思います。
データの型
上のurls.pyには「int」が記述されていていますが、これは「整数」を意味するものです。
プログラミングにはデータの型というものがありますので覚えておきましょう。
int型(イント型)
整数を表すものです。Integer(インテジャー)の略です。
>>> int(10)
10
>>> int(3.14)
3
str型(ストリング型)
文字列を表すものです。String(ストリング)の略です。
文字列と数字を連結したい時、数字を文字列として使うためによく使われます。
>>> print(20 + 1)
21
>>> print("年齢:" + 20)
TypeError: can only concatenate str (not "int") to str
# strと連結できるのはstrだけです。とエラーがでます。
# 20を数字ではなく、文字列にしてあげます。
>>> print("年齢:" + str(20))
年齢:20
ちなみに、文字列は「”何かの文字”」のように「”(ダブルクオテーション)」や「’(シングルクオテーション)」で囲ってあげると、システムが勝手に文字列と判断します。先程書いた、viewやfストリングスでも「” “」が使われていましたね!
「”」と「’」の使い分けは好みですが、「’ That’s ~ ‘」のように文字列の中に「’」が使われていたら、どこからどこまでが文字列か分からなくなるので、「” Taht’s ~ “」のように「”」で囲ってあげる必要があります。
float型(フロート型)
浮動小数点数(ふどうしょうすうてんすう)を表すものです。簡単に言えば小数点があるものです。
>>> float(3)
3.0
>>> float(3.14)
3.14
実用的なview
現在のindex関数は、単に文字列を返すだけのものでしたが、今度はQuestionモデルの最新のデータ(オブジェクト)5つを取得して、htmlに表示できるようにします。
from importを追加し、index関数を次のように変更してください。
from django.http import HttpResponse
from django.shortcuts import render # renderを呼び出す
from .models import Question # モデルのQuestionを呼び出す
def index(request):
# 最新のQuestionのデータ(オブジェクト)を5つ取得
latest_question_list = Question.objects.order_by('-pub_date')[:5]
# contextの中に入れる
context = {
'latest_question_list': latest_question_list
}
return render(request, 'polls/index.html', context)
この形はDjangoの基本でもあるので覚えておきましょう。
モデル名.objects.メソッド
Question.objects.order_by()は、Questionの全てのオブジェクト(データ)をorder_by(‘-pub_date’)日付が最新の順に並べ替える、という処理をしています。pub_dateにマイナスがないと古い順になります。
pub_dateはモデルのフィールド名です。models.pyのQuestionモデルでフィールドを設定しているので確認してみてください。
[:5]は、最初から5つ目までを意味します。[5:]だと最後から5つめまでとなります。objectsの後にあるメソッドは、Djangoが予め用意してくれている関数で、モデル内のobjectsにどういう処理をするか指定します。
よく使うメソッドの例として次の3つがあります。
- モデル名.objects.all()
モデルのオブジェクト(データ)全てを取得 - モデル名.objects.get(条件)
モデルから条件に一致したものを1つだけ取得(該当するデータが無いとエラー) - モデル名.objects.filter(条件)
モデルから条件に一致したデータをリストで取得
context
context(コンテクスト)の変数名は何でも良いのですが、Djangoでは慣習としてcontextが使われています。
contextには辞書を代入しています。この「辞書」というのが重要なので覚えておいてください。
pythonには、リスト、タプル、辞書が存在します。
- リスト
[ ]角括弧で囲ってあるものをリストと言います。 - タプル
( )丸括弧で囲ってあるものをタプルと言います。中身が1つの場合は値の後に「,」を付けます。 - 辞書
{ }波括弧で囲ってあるものを辞書と言います。
リストは中身の変更・追加ができるが、タプルにはそれができないという違いがあります。
# リスト
>>> list = ["a", "b", "c", "d", "e"]
# 1番目を取得
>>> list[1]
b
# タプル
>>> tuple = ("a",)
>>> tuple = ("a", "b", "c", "d", "e")
# 1番目を取得
>>> tuple[1]
b
# 辞書
# a=1、b=2, c=3として扱われる
>>> dict = {"a":1, "b":2, "c":3}
# aのデータを取得
>>> dict["a"]
1
辞書であるcontextの場合、”latest_question_list”を指定してあげると最新の5つのオブジェクト(データ)が入ったリストを取得できることになります。
このcontextの中身はhtmlで変数として扱えます。(後述します)
render(request, ‘アプリ名/~~.html’, context)
renderはレンダリングするという意味なのですが、簡単に言うと引数で指定したhtmlとcontextを元に画面を表示してくれます。
関数(def)でページで表示する場合は、return render(request, ‘~~.html’, context)の形がお決まりなので覚えておきましょう。
index.htmlを作る
上で書いたように、renderにはhtmlファイルが必要になるので作成していきます。
pollsアプリの中に「templates」ディレクトリを作成し、さらにその中に「polls」ディレクトリを作成してください。templatesには「s」がついているので忘れないように。

必ずtemplatesディレクトリの中にアプリ名のディレクトリを作るようにして下さい。これをしないとDjangoが正しいhtmlファイルを見つけることが出来ずエラーになります。
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>投票はありません。</p>
{% endif %}
重要な部分だけ取り出し解説します。
if文
条件を指定して処理を分ける方法です。よく使うので覚えておきましょう。
通常、HTMLでif文は使えないのですが、Djangoが{% if 変数 %}で特別に使えるようにしてくれています。
上記の場合以下のような表示になります。
{% if latest_question_list %}
もし、latest_question_listのデータが「あれば」、このブロックを表示します。
{% else %}
それ以外は(無い場合も)このブロックを表示します。
{% endif %}
for文
中身を順番に取り出す時に使います。よく使うので覚えておきましょう。
for文も通常HTMLでは使えないのですが、Djangoが{% for 変数 in リスト %}で特別に使えるようにしてくれています。
# for文の例
# 名前が入ったリストを用意します
>>> name_list = ["taro", "hana", "yamada", "sasaki"]
# for文でリストから一つずつ取り出します。
# nameの部分は好きな変数でOKです。
>>> for name in name_list:
print(name)
# name_listの中身が順番に出力されます。
taro
hana
yamada
sasaki
今回の場合、latest_question_listの中身を一つずつquestionに代入して出力しています。
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
さらにその中に{{ question.id }}と{{ question.question_text }}がありますね!
これはfor文でオブジェクトを取り出すだびに、そのquestion(オブジェクト)のidとquestion_textを取得しています。
- {{ question.id }}
html側で、questionのidを取得できる - {{ question.question_text }}
html側で、questionのquestion_textを取得できる
このように、1つのオブジェクトから特定のフィールドを取り出す場合は、{{ 変数.モデルのフィールド名 }}で取得できます。{% %}と{{ 変数 }}の形はhtml内で非常によく使うので覚えておきましょう!
index.htmlができたので、さっそく「http://127.0.0.1:8000/polls」にアクセスしてみましょう!
まだQuestionには1つのオブジェクト(データ)しか入ってないので、「what’s up?」だけが表示されたと思います。
urlを修正する
上記の<a href=”url”>のurlは、ハードコードされていてDjnagoではナンセンスな書き方とされています。
以下の部分を修正しましょう。
# /polls/{{ question.id }}/の部分がハードコードされているのでNG
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
# このように修正
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
urlを呼び出す場合は、{% url ‘アプリ名:pathのname‘ 変数 %}という形を使います。
こうすることで、後でurls.pyのpathを変えたい時など、html側を修正しなくても良くなります。リンクが一つだったら良いですが、様々なページで沢山使われていたら全てのURLを修正しなくてはいけないので大変ですね。
アプリ名とpathのnameはこの部分を指しています。

- index関数を呼び出すURL
{% url ‘polls:index’ %} - detail関数を呼び出すURL
{% url ‘polls:detail’ 変数 %} - results関数を呼び出すURL
{% url ‘polls:results’ 変数 %} - vote関数を呼び出すURL
{% url ‘polls:vote’ 変数 %}
detailページを作る
views.pyのdetail関数を修正します。
from django.shortcuts import render, get_object_or_404 # 追加
# detailを修正
def detail(request, id):
question = get_object_or_404(Question, id=id)
context = {
'question': question
}
return render(request, 'polls/detail.html', context)
get_object_or_404()というのが出てきましたが、これはQuestion.objects.get(id=question_id)と同じ結果が得られます。オブジェクトが無かった場合のエラーの結果が違うだけです。
慣れないうちは、モデル名.objects.get()を使って、慣れてきたらget_object_or_404()にしていくと良いかもしれません。
detail関数は出来たので、templates/pollsにdetail.htmlを作り以下の内容を保存します。
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
{{ question.question_text }}で質問が、for文で質問の選択肢{{ choice.choice_text }}を一つずつ取り出して表示しているコードになります。
for文のquestion.choice_set.allは、この質問に紐付いている選択肢のリストが入っています。こういった紐付けをリレーションシップと言います。choiceモデルのquestionには、ForeignKey(フォーリン・キー)を設定したので紐付けできる状態になっています。
リレーションシップは非常に重要な項目なのですが、少し混乱すると思うので詳しくは別の記事で解説したいと思います。取り敢えず今は名称だけでも覚えておいてください。
- ForeignKey(フォーリン・キー)
外部キーとも言います。1対多の関係の時に使います。今回の場合、質問1つに対して、選択肢が多数の関係です。 - ManyToMany(メニー・トゥー・メニー)
多対多の関係の時に使います。例えば、ブログのカテゴリーやタグのフィールドを作る場合です。1つの記事は複数のカテゴリー(多数)を持つことができ、カテゴリーの場合も、1つのカテゴリーが複数の記事(多数)を持つことができる関係です。
まとめ
# 基本の形
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)
# オブジェクトの操作
Question.objects.all() # 全てを取得
Question.objects.get(条件) # 1つしかないオブジェクトを取得
Question.objects.filter(条件) # 複数のオブジェクトをリストで取得
# if文
if ◯◯: # もし◯◯があれば
ここを実行
else: #それ以外は
ここを実行
# for文
# リストの中身を一つずつaに代入して出力
for a in list:
a
<!-- URLの取得 -->
{% url 'app_name:path name' 変数 %}
<!-- htmlでのif文 -->
{% if ◯◯ %} <!-- ◯◯があれば -->
ここを表示
{% else %} <!-- それ以外の場合 -->
ここを表示
{% endif %}
<!-- htmlでのfor文 -->
{% for a in list %}
{{ a }}
{% endfor %}
<!-- 変数の表示 -->
{{ a.id }} <!-- aのidを取得 -->
{{ a.フィールド名 }} <!-- aのフィールドの値を取得できる -->
覚える事が多く感じたかもしれませんが、頻繁に使うのですぐ身につくと思います。