pyhaya’s diary

機械学習系の記事をメインで書きます

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_idviews.indexに引数として渡すことです。例えばURL /polls/4にアクセスすると、question_id=3となりviews.detailに渡されます。

views.pyを編集する

では、views.pyindex関数が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.pymodels.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を登録してみると面白いかもしれません。

まとめ

今回書いたことは以下の3点です。

  • URLからviews.pyに引数を渡してページの見た目を操作した
  • データベースからデータをとってきてビューに反映した
  • HTML内にPython風コードを入れて、Pythonでページの見た目を変えられるようにした

pyhaya.hatenablog.com