Djangoのチュートリアル 3 ビューとモデルを組み合わせる
Djangoのチュートリアルの第三弾です。前回までの記事はこちらです。
pyhaya.hatenablog.com
pyhaya.hatenablog.com
今回行うことは、前回作成したモデルと前々回作成したビューを組み合わせて、実際のウェブページにモデルを組み込むことです。
サイトURLとビューを結びつける
最初に、最も簡単なものとしてサイトのURLをビューに反映させてみます。例えば、/polls/4
を訪れたらここは4番のページだよといった感じで表示されるようにしたいと考えます。
urls.py
を編集する
このような機能を実現するためには、まずURLの情報をビューに渡す必要があります。そのような機能はurls.py
に書くことができます。
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'), # <- この行を追加 ]
'/
という文が増えたことがわかります。この一文の役割は、int型の変数question_id
をviews.index
に引数として渡すことです。例えばURL /polls/4
にアクセスすると、question_id=3
となりviews.detail
に渡されます。
views.py
を編集する
では、views.py
のindex
関数がquestion_id
を引数として受け取れるように変更しましょう。
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def detail(request, question_id): # <- question_idを引数リストに入れた return HttpResponse("Hello, World. This is polls application number {}" .format(question_id))
これで、python manage.py runserver
としてサーバーを起動してhttp://127.0.0.1:8000/polls/4/
のようなページにアクセスすると、「Hello, World. This is polls application number 4」のように表示されるはずです。
モデルとビューを結びつける
データベースからデータをとってくる
次に、データベースからデータをとってきてそれを表示してみます。そのためには、ビューをどうにかしてデータベースにつなげる必要があります。データベースには、models.py
に書かれているモデルが登録されていることを考えると、views.py
とmodels.py
を結び付ければよいことがわかります。
polls/views.py
from django.shortcuts import render from .models import Question # Create your views here. def index(request, question_id): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list' : latest_question_list} return render(request, 'polls/index.html', context)
さて、先ほど書いたindex
関数は跡形もありません。一行ずつ見てみましょう。
Question.objects.order_by('-pub_date')[:5]
Question
というのはmodels.py
中のQuestion
クラスのことであることはよいと思います。そのあとのobjects
以下でデータベースの中からQuestion
のオブジェクトとして登録されているものをとってきます。order_by
では、並び替えて表示しろという指示です。何について並び替えるのかを指定しているのが引数です。Question
クラスにpub_date
というフィールドを作ったのを覚えているでしょうか?忘れた人は第二回の記事を参照してください。order_by
の引数に'-pub_date'
をとることによってpub_date
が新しいほうから古いほうへ並び替えられます('pub_date'
なら逆順になります)。[:5]
を指定することによって最初から5個だけ取り出します。
データベースからデータを取り出す方法には様々あります。ほかのものにも興味がある人は、以下のサイトが詳しいです。
qiita.com
context = ...
contextは辞書型のオブジェクトです。今回の場合には、キーとしてlatest_question_listが、そして対応する値には、上で取得したデータが格納されています。コンテクストのキーは、HTMLファイルを編集するときに使います。キーの名前を
{{ キーの名前 }}
のようにして書くことによって値がHTMLに埋め込まれます。このコンテクストはreturn
の行で、レンダリングされてindex.htmlに反映されます。
HTMLを作る
HTMLファイルの置き場
今までは、views.py
のなかでページの見た目を決めてきました。しかしこれには限界があります。やはりWebページを作るのはHTMLのほうが得意ですし実績もあるので、Djangoでもページの見た目は最終的にHTMLに投げます。
しかし、Djangoで使うHTMLファイルは、一般的なHTMLファイルとは少し違います。Python風の文が埋め込まれています。さて、新しいファイルを作るときにいつも問題になるのが、ファイルをどこに置くか問題です。一般的には、各アプリケーションごとにtemplatesディレクトリを作って、その中にアプリケーションの名前が付いたフォルダを作って、その中に入れます。なので今回は、次のような階層構造になるはずです。
pollsディレクトリ内部
.
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│ ├── 0001_initial.py
│ ├── __init__.py
│ └── __pycache__
│ ├── 0001_initial.cpython-36.pyc
│ └── __init__.cpython-36.pyc
├── models.py
├── __pycache__
│ ├── admin.cpython-36.pyc
│ ├── apps.cpython-36.pyc
│ ├── __init__.cpython-36.pyc
│ ├── models.cpython-36.pyc
│ ├── urls.cpython-36.pyc
│ ├── views.cpython-35.pyc
│ └── views.cpython-36.pyc
├── templates # <- ここ
│ └── polls
│ └── index.html
├── tests.py
├── urls.py
└── views.py
HTMLを書く
では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>
見た目は、ふつうのHTMLみたいな感じですが、変な行が何行かあります。7行目とか、ふつうのHTMLでは見られません。これはPythonが理解できるコードです。確かに、普段Pythonで使いそうな感じの構文です。しかし、上で書いたようにこれはあくまでPython風です。13行目のendfor
とかはPythonでは使いませんし{{ }}
や{% %}
もPythonでは使いません。これは、HTMLの文法で書かれた範囲とPythonの部分を明確に分けるための表示です。
if文やfor文を使うときには{% %}
を使い、変数を使いたいときには{{ }}
を使います。Pythonの文が使われているところを見ると、latest_question_list
の文字が見えます。これは先ほどviews.py
でコンテクストのキーとして登録したものです。このようにしてPythonの変数をHTML上で使います。
サーバーを走らせてhttp://127.0.0.1:8000/polls/1/を見てみると、前回登録した「What's up?」が表示されていると思います。これだけだと寂しいので、pub_dataを変えて、様々なQuestionを登録してみると面白いかもしれません。