Djangoのページにカスタムヘッダ(タグ)を動的に挿入する。
<head>
タグ中に独自のヘッダ(タグ)を動的に挿入する手段が欲しかった。
単純にモデルで管理してテンプレート内で展開すればいいことに気づいたのでメモを残しておく。
基本方針
- ヘッダは複数でも可
- ヘッダは追加後の修正も簡単にできる
- ヘッダは
admin
サイトから操作可能(ソースをいじる必要はなし)
まあ普通のような気もする。admin
サイトから操作できれば上の2つは達成できるようなものだから、admin
サイトで操作さえできれば、ほぼできたようなものだ。残る問題はhtmlでどう読み込めばいいかくらいになる。
こういう感じにする
テンプレートのレンダリングのときに、以下のadminサイトから変更できるタグ
を挿入可能にする。
<html>
<head>
<!-- テンプレートで書いてあるヘッダタグ -->
<!-- adminサイトから変更できるタグ -->
<meta name="サンプル" content="metaタグ以外も可能">
</head>
<body>
<!-- ページの中身 -->
</body>
</html>
やること
ここからは実装。と言ってもそんなにすることはない。過去の記事を活かせば難しくない。
- カスタムヘッダをモデルとして定義
admin
サイトで操作可能にする- htmlレンダリング時、コンテキストにカスタムヘッダを挿入する
- テンプレートでカスタムヘッダをレンダリングするようにする
これらを実装すればいい。順に説明する。
実装
カスタムヘッダをモデルとして定義
まずは<app>/models.py
にカスタムヘッダを定義する。
from django.db import models
class CustomHeader(models.Model):
name = models.CharField(max_length=40)
tags_text = models.TextField(
help_text='Some tags text(html format) in html > head')
def __str__(self):
return self.name
CustomHeader
は、name
とtags_text
の2つのフィールドを持つ。
name
はカスタムヘッダの識別用の名前であり、これ自体はレンダリングはしない。
tags_text
はレンダリングする内容。エスケープを考慮する必要はなく、<
や>
などもそのまま含めていい。
adminサイトで操作可能にする
admin.py
に記述しないとadmin
サイトには現れないので、忘れず記述する。
ここのあたりはDjangoのチュートリアルのpollアプリケーション
にもあったと思う。
from django.contrib import admin
# <app>/models.pyをインポート
from . import models
# Register your models here.
admin.site.register(models.CustomHeader)
...
これだけ。あとは…マイグレーションも必要か。python manage.py makemigrations
でよかったと思う。
これで/admin/
にアクセスしてログインすれば、CustomHeader
モデルが見える。
コンテキストにカスタムヘッダを挿入する
以前書いた記事で使ったコンテキストプロセッサを使う:
実装したコンテキストプロセッサは次のようなもの:
from django.http import HttpRequest
from app.models import CustomHeader
def add_head_tags(request: HttpRequest):
""" カスタムヘッダを挿入するためのコンテキストを付加するコンテキストプロセッサ """
head_tags = [i.tags_text for i in CustomHeader.objects.all()]
return {'head_tags': head_tags}
やっていることはとてもシンプル。コンテキストのhead_tags
にCustomHeader
モデルの全てのオブジェクトのtags_text
を格納するだけ。特定のものだけにしたいのならば、ここでフィルタリングなどを行なっておけばいいだろう。
そして、Djangoの設定ファイルで、TEMPLATES
のOPTIONS
のcontext_processors
へこのコンテキストプロセッサを追加するのを忘れないようにする。
テンプレートでカスタムヘッダをレンダリングする
ここまできたらテンプレートでレンダリングするだけだ。このappでは、全てのページは同じベーステンプレートを使用しているので、そのベーステンプレートファイルの<head>
部分を変更すればいい。
...
<head>
...
{% autoescape off %}
{% for head_tag in head_tags %}
{{ head_tag }}
{% endfor %}
{% endautoescape %}
</head>
...
エスケープしないようにして、タグを展開するだけ。 Djangoのテンプレートの自動エスケープについては、以前書いた: Django Template Languageでの変数のエスケープ回避 | ikapblog
これで実装は終わり。
動作確認
admin
サイトでデータを追加するのが楽だろう。admin
サイトを使いたくないときは、python
を起動して直接操作するのだと思う。
作用のないタグを適当に追加してみて、ページを開いてソースを確認すればヘッダ(タグ)が追加されているのがわかるはず。
そのほかの実装方法
他の実装方法も多々あると思うので思いつく方法をメモしておく。モデルとして管理しておくのはソースを変更しないで単独で実現する上でほぼ必須となるので、モデルの使用は前提としておく。 なので、他の実装方法といっても、レンダリングの他の方法くらいの意味になる。
上記方法に対してのメリット・デメリットを書いておく。
コンテキストを使わずに、カスタムテンプレートタグを利用する
コンテキストに格納するのでなく、カスタムタグの呼び出し時にオブジェクトを呼び出す方法。
- メリット
- コンテキストからカスタムヘッダを取り出すためのキーを意識する必要がなくなる
- カスタムタグ(
{% add_headers %}
など)を書いておけばいい - コンテキストプロセッサが不要になる
- デメリット
- カスタムタグを用意する必要がある
こちらの方が簡単かも…。コンテキストに格納するキーを一致させる必要がないのは大きなメリットだと思う。
おわりに
アクセス解析などでは、ヘッダにタグを設置するよう求められることが多いのでDjangoでそういうことをしたいのであれば、上のような実装は必要になる。
この実装なら後からの修正や追加・削除が簡単に済むので管理が簡単になる。他の方法もあるのかもしれないが、その辺りの調査はまた今度。
以上です。
Django関連書籍(広告)