3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Django 2.xでbase.htmlにmodelを表示する方法

Last updated at Posted at 2019-01-29

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というテンプレートタグ・フィルターを実装します。

myfilter.py
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側で、実装したテンプレートタグ・フィルターを呼び出すには以下の通りに記述します。

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のデータを取得し、格納しております。

middleware.py
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を参照する

base.html
<h1><a href="/">{{ request.profile.title }}</a></h1>
<h4>{{ request.profile.detail }}</h4>

以上で、base.htmlにmodelを表示する方法は終わりです。

おまけ ~modelをキャッシュする~

先ほど挙げた2つの方法ですが、両方とも毎回モデルを取得する(データベースにクエリを発行している)のが気になります。
そこで、別の方法を調べたところ、cached_propertyなるものがありました。

models.py
from django.utils.functional import cached_property

class Profile(models.Model):

    @cached_property
    def get_profile(self):
        return self.objects.get(pk=1)
     

これで毎回呼び出しても、モデルの取得結果がキャッシュされているので安心ですね。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?