Django入門: オブジェクトを描画 ~ 簡単な一行掲示板アプリを作る その10【Windows10】

87, 2020-10-23

目次

はじめに

この記事は「Djangoで一行掲示板を作ろう」という趣旨のシリーズの記事です。

前回までにDjangoのプロジェクトとアプリを作成し、ルート情報とビューを接続し、テンプレートを描画して、モデルを作りマイグレーションを行い、ビューでオブジェクトを取得しました。

今回から作成したPostモデルを使ってテンプレート内で描画していきたいと思います。

また前提としてOSはWindows10, シェルはコマンドプロンプトを使います。
Pythonの仮想環境を使っていますのでvenv\Scripts\activateを実行してある前提です。
仮想環境についてはこちらの第一回の記事をご覧ください。

それから初期位置の作業フォルダはプロジェクト内のmanage.pyがあるフォルダです。

テンプレートファイルの構成

前回までのテンプレートファイルはbbs\templates\bbs\home.htmlのように1つだけのテンプレートで構成していました。
今回の例ではテンプレートファイルは1つだけの構成でも可能なんですが、より柔軟性のある構成をご紹介したいので、テンプレートファイルを1つ増やしたいと思います。

テンプレートファイルは別のテンプレートファイルを継承することが可能です。
つまりベースとなるテンプレートファイルを1つ作り、そのベースを継承してhome.htmlを作ってみたいと思います。
こうすることで、共通したHTMLをベースとなるテンプレートファイルに記述することが可能になり、home.htmlの負担を減らせます。
また、一部のHTMLを共通化することで色々なテンプレートファイルで統一が取れるようになります。

今回は↓のようなテンプレートファイルの構成にしたいと思います。

  • bbs\templates\bbs\base.html

  • bbs\templates\bbs\home.html

base.htmlの編集

エディタでbbs\templates\bbs\base.htmlを開き↓のように記述します。

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

内容的にはただのHTMLに近いものですが、テンプレートファイル特有の記述を使っている所を解説します。

  <title>{{ title }}</title>

↑の部分はコンテキスト内のtitle変数をHTMLのtitleタグ内に出力しています。
こうすることでビューからWebページのタイトルを指定できるようになります。
変数の出力は↑のように変数を{{ }}で囲います。

{% block content %}
{% endblock %}

↑はテンプレートファイル内でcontentという名前のブロックを作っています。
「ブロック」というのはテンプレートファイル内の「区画」のことです。
継承元、つまりこのbase.htmlなどに↑のようにブロックを作ると、このbase.htmlを継承したテンプレートファイルは、このブロックに別のHTMLを注入できるようになります。
つまり↑は「ここにcontentというブロックを作っておくから、継承した人は適当に使ってね」という感じの記述です。

このcontentブロックはbodyタグ内にあるので、このcontentブロックに注入されたHTMLは↑のbodyタグ内に展開されることになります。

home.htmlの編集

次にbbs\templates\bbs\home.htmlをエディタで開き↓のように編集します。

{% extends 'bbs/base.html' %}

{% block content %}
<h1>{{ title }}</h1>
{% endblock %}

モデルは?

はい。モデルは少々お待ちください。
その前に↑のコードを解説します。

{% extends 'bbs/base.html' %}

上の部分はextendsという命令文を実行しています。
テンプレートファイルのextends文は第1引数に継承元のテンプレートファイルのパスを指定します。
↑の場合はbbs/base.htmlになっていますが、これはbbs/templates/bbs/base.htmlのことです。
bbs/templatesが省略されていることに注意してください。

この命令文を実行することで、home.htmlbase.htmlを継承したことになります。
継承しているので、base.html内のcontentブロックにHTMLを注入できるようになります。
また、コンテキスト内の変数はbase.htmlhome.htmlで共有されるようになります。

{% block content %}
<h1>{{ title }}</h1>
{% endblock %}

↑のコードで継承元のbase.html内のcontentブロックに<h1>{{ title }}</h1>というHTMLを注入しています。
<h1>{{ title }}</h1>h1タグ内にtitle変数を出力しているところです。

開発用サーバーで動作確認

ここまでの変更を開発用サーバーで確認してみましょう。

> python manage.py runserver 0.0.0.0:8123

特に問題がなければ↓のように表示されると思います。

【0087】ss00.png

モデルを出力する

さきほどのhome.htmlを↓のように改造します。

{% extends 'bbs/base.html' %}

{% block content %}
<h1>{{ title }}</h1>
<ul>
  {% for post in posts %}
    <li>{{ post.id }}: {{ post.content }}</li>
  {% endfor %}
</ul>
{% endblock %}

↓の部分が新しく加わりました。

<ul>
  {% for post in posts %}
    <li>{{ post.id }}: {{ post.content }}</li>
  {% endfor %}
</ul>

Djangoのテンプレートではfor文でループ処理を書くことが出来ます。

  {% for post in posts %}
  ...
  {% endfor %}

↑の部分ではpostsというコンテキスト内の変数(これはQuerySetですね)をfor文で回して、postという変数に展開しています。

    <li>{{ post.id }}: {{ post.content }}</li>

↑の部分ではpostの属性idcontentliタグ内に出力しています。
先述したようにmodels.Modelを継承したモデルは自動でidというフィールドを定義します。
contentは今シリーズで私たちが作ったフィールドです。

postsはビュー内のPost.objects.all()で取得したQuerySetです。
QuerySetはこのようにテンプレートファイル内のfor文で回すことが出来ます。
そしてQuerySetfor文で回すとPostのオブジェクトとして展開することが出来ます。

では↑の変更を加えた上で再度runserverで動作確認をしてみましょう。
すると先ほどと変わらない画面が出力されているはずです。
これはそのはずで、Postというモデルを作成しマイグレーションも行いましたが、肝心のデータはまだDBに保存していないので、postsの中身も空なわけです。

おわりに

今回はテンプレートファイル内でPostのオブジェクトを描画する所までやりました。
次回以降から管理サイトを使ってPostのデータを追加してみたいと思います。

お楽しみに