今回のテーマは「ビューとテンプレートの基礎」です。今までは細々と設定作業ばかりでDjangoの面白さを実感出来なかったかも知れません。いよいよ特定のURLに対してHTMLを出力していきますよ。
※本ページはアプリケーションの作成まで読まれた方を対象としています。そのためサンプルソースコードが省略されている場合があります。
Djangoにおけるビューとテンプレート
DjangoはMVT(Model, View, Template)モデルのフレームワークを自称しています。よく知られているMVCモデルとよく似ていますが、MVCモデルにおけるViewが「情報をどのように見せるのか?」という観点で作られるのに対して、DjangoにおけるViewは「表示すべき情報は何か?」を用意しテンプレートに渡す役割を果たしています。「どのように見せるか?」という出力についてはテンプレートが担います。即ちViewはユーザーのアクションに応じてビジネスロジックを担うモデルに通知し、ユーザーに見せる情報を受け取りテンプレートに渡す仕事をします。詳細は公式ドキュメントを参照下さい。
Hello World
とにかく文字を画面に出しましょう。
base/views.py
from django.http import HttpResponse
from django.template import loader
def top(request):
return HttpResponse('Hello World')
このviews.pyに追加したtop関数をURLと結びつけるためbase/urls.pyを修正します。
base/urls.py
from django.urls import path
from . import views
app_name = 'base'
urlpatterns = [
path('', views.top, name='top'),
]
ではブラウザで見てみましょう。
(venv)$ ./manage runserver 0.0.0.0:8080
ブラウザでlocalhost:8080にアクセスします。Hello Worldが出ましたね。
templatesディレクトリを設定する
テンプレートを使いたいのですが、まずはテンプレートをどこに配置するか決定しましょう。Djangoのデフォルト設定では各アプリケーション内のtemplatesディレクトリから探す設定となっています。 図にすると
mysite
│└app1
│ └templates
│ └app1
│ └template.html
│
└app2
└templates
└app2
└template.html
というイメージです。一方、テンプレートファイルを1つのtemplatesディレクトリで管理する方法もあります。その場合は
mysites
└templates
│└app1
│ └template.html
└─app2
└template.html
...
となります。ディレクトリ構成は好みもありますし、プロジェクトの方針にもよりますが、筆者は後者が好みです。前者の構成はアプリケーションがテンプレートを含んだモジュールとして独立することが念頭にあります。今回は後者の設定で進めます。もし前者のスタイルとする場合は以下の設定は不要です。 mysites/settings.pyのTEMPLATES部分の設定を書き換えます。
+ import os #インポートされていない場合はインポートする
- 'DIRS': [],
+ 'DIRS': [os.path.join(BASE_DIR, 'templates')],
templatesディレクトリをプロジェクト直下に作成し、その中にbaseディレクトリを生成しましょう。
(venv)$ cd mysite #プロジェクト直下にいない場合は移動する
(venv)$ mkdir -p mysite/templates/base
テンプレートを使ってみる
baseアプリケーション用のテンプレートファイルを生成します。
mysite/templates/base/top.html
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta http-equiv="content-language" content="ja">
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>テンプレートテスト表示</p>
</body>
テンプレートを使用するようにbase/views.pyのtop関数も以下のように書き直します。
base/views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
def top(request):
template = loader.get_template('base/top.html')
ctx = {'title': 'Django学習ちゃんねる(仮)'}
return HttpResponse(template.render(ctx, request))
ではブラウザで確認してみましょう。
(venv)$ ./manage runserver 0.0.0.0:8080
ちなみに毎回runserverを実行することはなく、実行したままソースを書き換えて保存すると自動的に反映されます。(一部settingsに関わるものなどは反映されませんので再起動が必要)
なんとも恥ずかしいタイトルですがスルーしてください。views.pyで渡したtitleパラメータがテンプレートに渡されていることが確認されました。Djangoテンプレートはdict型の変数でパラメータを渡し、テンプレート側では「{{}}」でパラメータ名を囲うことで表示されます。 さて、表示されましたが、テンプレートに表示する度に先程のようにテンプレートを読み込んで表示するのは面倒なのでショートカットが用意されています。先程のviews.pyは以下のように書き換え出来ます。
base/views.py
from django.shortcuts import render
# from django.http import HttpResponse
# from django.template import loader
def top(request):
# template = loader.get_template('base/top.html')
ctx = {'title': 'Django学習ちゃんねる(仮)'}
# return HttpResponse(template.render(ctx, request))
return render(request, 'base/top.html', ctx)
loaderもHttpResponseも不要になりスッキリ書けますね。renderを使用すると任意のテンプレートにコンテキスト(テンプレートに変数を渡す入れ物と考えて下さい)を渡して表示することが出来ます。
最後に
現段階ではHTMLを出力するだけでCSSやjavascript等のファイルは読み込んでいません。モダンなWEBアプリにCSS,JSは必須(もはや主役)ですので配置方法を見ていくことにします。
Sponsored Link
初心者で何もわからないまま、できるだけご教示いただいたとおりに書いているはずなのですが、
RecursionError: maximum recursion depth exceeded while calling a Python object
と表示され、先に進めません。どこが間違っているのでしょうか…
THさん
コメントありがとうございます。記事の内容に誤りがあったため、ご迷惑をおかけしました。
間違っていた箇所ですが、base/urls.pyに関する記述が2回出てきたのですが、2回目はmysites/urls.pyに関する記述のだったのですが、ファイル名が誤っていたために混乱を招いてしまいました。二回目に出てきたurls.pyに関する部分は混乱の元ですので削除しました。
エラーの原因はbase/urls.pyの中で再帰的にbase/urls.pyの中身を呼び出したことと思われます。base/urls.pyに関しては記事前半で修正したままのものを使用すれば問題ないはずです。
クロさま
つい先日から掲示板アプリを作ろうとDjangoの勉強を始めたのですが、エラーの連続で心が折れかかっている時に本サイトを見つけ、説明のわかりやすさ、丁寧さに感動しております。
本当にありがとうございます。
本題なのですが、base/urls.pyのname = ‘base’に関して、この段階ではエラーが出なかったのですが、1-13でlocalhost:8080/thread/1を表示しようとする際に
‘base’ is not a registered namespace
というエラーが出ました。
name = ‘base’をapp_name = ‘base’とすることにより解決しましたが、一応参考までに報告させていただきます。
環境:Django 2.2, python 3.6
dax
「テンプレートを使ってみる」以降のbase/views.pyを編集すると
TemplateDoesNotExist at /
base/top.html
というエラーとなります
あとりさん
top.htmlテンプレートの配置場所が正しくないようなので、正しい場所mysite/templates/base/以下に配置してみてください。
またsettings.pyの設定も正しいか見直して下さい。
クロさま
私もDjangoのテストとして利用させていただいております。
ありがとうございます。
私も下記の事象が発生し、app_name = ‘base’ で画面は表示できました。
一応参考までに報告させていただきます。
『本題なのですが、base/urls.pyのname = ‘base’に関して、この段階ではエラーが出なかったのですが、1-13でlocalhost:8080/thread/1を表示しようとする際に‘base’ is not a registered namespaceというエラーが出ました。
name = ‘base’をapp_name = ‘base’とすることにより解決しましたが、一応参考までに報告させていただきます。』
Python 3.9.0
django 3.1.2
selecao11 さん
返信遅くなり申し訳ありません。ご指摘ありがとうございます。
記事中のコード修正いたしました。