Django Girl TutorialでWebアプリケーションを書いてる時に、「ブログの基本情報はbase.html(ベースとなるtemplate)に記載しているけど、それをテーブル化してModelから参照したデータを表示したいなぁ」と思ったことがあったので、その方法2つを備忘録的に記載します。
方法1.テンプレートタグ・フィルターを実装する
templateからpython側の処理を呼び出したい時に使用するテンプレートタグ・フィルターを実装し、それをbase.htmlで呼び出す方法です。
myfilter.pyを用意
テンプレートタグ・フィルターを実装するために必要なファイルを、以下の構成で用意します。
app/
├ __init__.py
├ admin.py
├ apps.py
├ model.py
├ templatetags/ ← ディレクトリを追加
│ │ __init__.py ← 空のファイルを用意
│ └ myfilter.py ← ここに実装
├ views.py
└ templates
└ base.html
※__init__.pyは該当ディレクトリをPythonディレクトリとして認識するために必要なファイルなので、必ず用意してください。
続いて、myfilter.pyにテンプレートタグ・フィルターを実装します。
ここでは、Profileモデルからpk=1のデータを取得し返却する、get_profileというテンプレートタグ・フィルターを実装します。
from django import template
from app.models import Profile
import markdown
register = template.Library()
@register.filter
def get_profile(value):
profile = Profile.objects.get(pk=1)
return profile
base.html側で、実装したテンプレートタグ・フィルターを呼び出す
base.html側で、実装したテンプレートタグ・フィルターを呼び出すには以下の通りに記述します。
{% load myfilter %}
・・・
{% with '' | get_profile as profile %}
<h1><a href="/">{{ profile.title }}</a></h1>
<h4>{{ profile.detail }}</h4>
{% endwith %}
テンプレートタグ・フィルターは引数が必須ですが、特に渡す値が無い為、ここでは''を渡しています。
方法2.middlewareを実装する
djangoでは、Viewの入出力タイミング(リクエストとレスポンス)をフック出来るMiddlewareというものを実装出来ますので、それを用いてモデルを参照します。
middleware.pyを用意
Middlewareを実装するためのファイル(middleware.py)を、以下の構成で用意します。
app/
├ __init__.py
├ admin.py
├ apps.py
├ model.py
├ middleware.py ← ここに実装
├ views.py
└ templates
└ base.html
続いて、middleware.pyを以下の通りに実装します。
Middlwareの実装方法の詳細については公式ドキュメントや、他の方の投稿記事の方が参考になります。
ここでは、request.blogProfileにProfileモデルからpk=1のデータを取得し、格納しております。
from blog.models import BlogProfile
class BlogProfileMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# リクエストへの前処理を記述
# reqeust.profileに、Profileモデルからブログ情報を取得する
request.proflie = Profile.objects.get(pk=1)
# 固定
response = self.get_response(request)
# レスポンスへの後処理を記述
return response
base.html側で、request.profileを参照する
<h1><a href="/">{{ request.profile.title }}</a></h1>
<h4>{{ request.profile.detail }}</h4>
以上で、base.htmlにmodelを表示する方法は終わりです。
おまけ ~modelをキャッシュする~
先ほど挙げた2つの方法ですが、両方とも毎回モデルを取得する(データベースにクエリを発行している)のが気になります。
そこで、別の方法を調べたところ、cached_propertyなるものがありました。
from django.utils.functional import cached_property
class Profile(models.Model):
@cached_property
def get_profile(self):
return self.objects.get(pk=1)
これで毎回呼び出しても、モデルの取得結果がキャッシュされているので安心ですね。