Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Djangoテンプレートエンジンを使いこなそう!
Search
Shinya Okano
October 06, 2023
Technology
3.1k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Djangoテンプレートエンジンを使いこなそう!
Shinya Okano
October 06, 2023
More Decks by Shinya Okano
See All by Shinya Okano
プロファイラを使ってPythonアプリをチューニングしよう
tokibito
2
1.4k
Pythonのデバッガーを使おう
tokibito
1
960
Djangoフレームワークの紹介_OSC北海道2019
tokibito
1
1.1k
DjangoCongressJP開催レポート
tokibito
0
100
Djangoフレームワークの紹介 OSC2018do
tokibito
0
2.9k
Other Decks in Technology
See All in Technology
製造現場での生成AIの活用、およびエージェントAIの実装のあり方、AVEVAの取り組み
iotcomjpadmin
0
180
「軸足」は 固定しなくていい - 熱量と強みで描く、しなやかなキャリアの形
kakehashi
PRO
1
290
フルAIで個人開発して学んだあれこれ / yuruai vol.1
isaoshimizu
0
150
AIペネトレーションテスト・ セキュリティ検証「AgenticSec」紹介資料
laysakura
2
7.7k
Kotlin 開発のツラミを爆破した話! / Explode the difficulty of Kotlin dev!
eller86
0
100
Microsoft のサポートとフィードバック総まとめ
murachiakira
PRO
0
120
AIは、人間らしい仕事の夢を見るか?─ AI時代のtoB/toEプロダクトを再設計する
techtekt
PRO
0
160
WebGIS AI Agentの紹介
_shimizu
0
590
Why is RC4 still being used?
tamaiyutaro
0
170
AWS Summit 2026で見えたSIerにとっての Amazon Quickの位置づけ
maf_0521
0
120
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
300
自分が詳しくない領域でAIを使う #プロヒス2026
konifar
20
7.9k
Featured
See All Featured
Designing for Timeless Needs
cassininazir
1
260
Facilitating Awesome Meetings
lara
57
7k
Building the Perfect Custom Keyboard
takai
2
800
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
140
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
370
エンジニアに許された特別な時間の終わり
watany
107
250k
Thoughts on Productivity
jonyablonski
76
5.2k
Believing is Seeing
oripsolob
1
160
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
400
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Transcript
Djangoテンプレートエンジンを 使いこなそう! DjangoCongressJP 2023 @tokibito
お前誰よ? • 岡野真也 • X (twitter): @tokibito • 株式会社ObotAI 取締役CTO
• 株式会社オープンコレクター 取締役 • Djangoフレームワークは2006年ごろから使ってる
アジェンダ • Djangoテンプレートエンジン概要 • アプリからの使い方 • テンプレート言語を使いこなす • テンプレートエンジンのカスタマイズ
Djangoテンプレートエンジン 概要
Djangoテンプレートエンジン • Djangoには、組み込みのテンプレートエンジンがあります。 • django.template
Djangoテンプレートエンジンの機能 • テンプレートを使って文字列を生成する • =レンダリングする • コンテキストを渡すことで、レンダリング時に動的に内容を変 更できる • テンプレート言語により、柔軟に出力内容を制御できる
• テンプレートローダーにより、テンプレートをファイルから読 み込める
テンプレートを使って 文字列を生成する
Django shellで試す >>> from django.template import engines >>> # テンプレートエンジンインスタンスの取得
>>> django_engine = engines["django"] >>> # テンプレート文字列をコンパイルして、Templateインスタンス生成 >>> template = django_engine.from_string("Hello {{ name }}!") >>> # コンテキストを指定してテンプレートをレンダリング >>> template.render({"name": "spam"}) 'Hello spam!' https://docs.djangoproject.com/en/4.2/topics/templates/#django.template.loader.engines
テンプレートにコンテキストを渡す • テンプレートにコンテキスト(context, 文脈)を渡すと、レンダ リング時に動的に内容を変更できる • キー(key)と値(value)の組み合わせで複数渡せる • Pythonの辞書を渡せる、と考えておけばOK
テンプレートのレンダリング テンプレート コンテキスト レンダリング結果 文字列 レンダリング
コンテキストを使う例 >>> from django.template import engines >>> # テンプレートエンジンインスタンスの取得 >>>
django_engine = engines["django"] >>> # テンプレート文字列をコンパイルして、Templateインスタンス生成 >>> template = django_engine.from_string("Hello {{ name }}!") >>> # コンテキストを指定してテンプレートをレンダリング >>> template.render({"name": "spam"}) 'Hello spam!' >>> # コンテキストを変更した場合 >>> template.render({"name": "egg"}) 'Hello egg!'
アプリからの使い方
Djangoドキュメントのチュートリアル • 「はじめての Django アプリ作成、その 3」 • https://docs.djangoproject.com/ja/4.2/intro/tutorial03/ • テンプレートファイルの作成、使い方の説明がある
ひとまずやってみる • プロジェクトのデフォルト設定で、テンプレートファイルを利用可能 • startappでmyappを作り、settings.pyのINSTALLED_APPSに追加してお く
from django.shortcuts import render # Create your views here. def
my_view(request): return render(request, 'spam.html', {'name': 'egg'}) myapp/views.py Hello {{ name }} myapp/templates/spam.html from myapp import views urlpatterns = [ path('', views.my_view), path('admin/', admin.site.urls), ] myproject/urls.py
None
コンテキストを使う例 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], #
任意のテンプレートディレクトリ追加 'APP_DIRS': True, # アプリのtemplatesを使うか 'OPTIONS': { 'context_processors': [ # コンテキストプロセッサ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
settings.py: BACKEND • テンプレートエンジンのバックエンド設定 • デフォルトはDjangoTemplates=Djangoテンプレートエンジン • 変更すると、Jinja2などのDjango以外のテンプレートエンジンを利 用可能 •
django.contrib.adminなど、Djangoに組み込まれている機能は、 Djangoテンプレートエンジンを前提にしている実装が多い • TEMPLATES設定はリストで複数記述できるので、Jinja2との併用 は可能 'BACKEND': 'django.template.backends.django.DjangoTemplates',
settings.py: DIRS • テンプレートファイルを配置するディレクトリ • 絶対パスで記述する必要がある。 'DIRS': [], # from
pathlib import Path # BASE_DIR = Path(__file__).resolve().parent.parent 'DIRS': [ BASE_DIR / 'templates', # プロジェクト直下のtemplatesディレクトリ ]
settings.py: APP_DIRS • アプリケーション内のtemplatesディレクトリを検索対象にす るかどうか • myapp/templates が検索対象となる。 'APP_DIRS': True,
settings.py: OPTIONS.context_processors • コンテキストプロセッサ、後ほど説明 'OPTIONS': { 'context_processors': [ # コンテキストプロセッサ
'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], },
View関数でテンプレートを使う from django.shortcuts import render # Create your views here.
def my_view(request): return render(request, 'spam.html', {'name': 'egg'}) myapp/views.py render関数は、便利なショートカット関数 render(request, template_name, context=None, content_type=None, status=None, using=None) https://docs.djangoproject.com/en/4.2/topics/http/shortcuts/#render
render関数の役割 • テンプレートファイルのロード • テンプレートのレンダリング • HttpResponseの作成
render関数を使わない場合 from django.http import HttpResponse from django.template import loader def
my_view(request): template = loader.get_template('spam.html') context = { 'name': 'egg', } return HttpResponse(template.render(context, request)) myapp/views.py
クラスベースビューでテンプレートを使う • django.views.generic.TemplateView • または、TemplateResponseMixinを継承したクラス
from django.views.generic import TemplateView class MyView(TemplateView): template_name = 'spam.html' def
get_context_data(self): context = super().get_context_data() context['name'] = 'egg' return context myapp/views.py from myapp import views urlpatterns = [ path('', views.MyView.as_view()), ] myproject/urls.py
テンプレート言語を使いこなす
テンプレート言語 • レンダリングの際に、テンプレート言語によって出力内容を変 更・制御できる • 変数: {{ 変数名 }} •
フィルター: {{ 変数名|フィルター:パラメータ }} • タグ: {% タグ名 パラメータ1 パラメータ2 ... %} • コメント: {# コメント #} https://docs.djangoproject.com/en/4.2/topics/templates/
テンプレート言語: 変数 • テンプレートに渡されたコンテキストを、テンプレート上で変 数として使用できる。 • {{ 変数名 }} >>>
template = django_engine.from_string("Hello {{ name }}!") >>> template.render({"name": "spam"}) 'Hello spam!'
変数: 辞書やリストへのアクセス def book_view(request): context = { 'book': { 'name':
'Django doc', 'pages': 200, 'tags': ['django', 'python'], }, } return render(request, 'book.html', context) myapp/views.py
name: {{ book.name }}<br> pages: {{ book.pages }}<br> tags: {{
book.tags }}<br> <br> {{ book.tags.0 }} {{ book.tags.1 }} myapp/templates/book.html • 辞書の場合、要素には “.キー名”でアクセスできる • リストの場合も、要素は “.index”でアクセスできる
None
テンプレート言語: フィルター >>> from datetime import datetime >>> template =
django_engine.from_string("Today is {{ value|date:'Y-m-d' }}") >>> template.render({"value": datetime(2023, 10, 7)}) 'Today is 2023-10-07' いろいろなフィルターがある https://docs.djangoproject.com/ja/4.2/ref/templates/builtins/#ref-templates-builtins-filters • 出力する前に、データを処理して、出力内容を変更できる • 変数に対してフィルターを設定する • {{ 変数名|フィルター:パラメータ }}
テンプレート言語: タグ >>> template = django_engine.from_string("Today is {% now 'Y-m-d'
%}") >>> template.render() 'Today is 2023-10-05' いろいろなタグがある https://docs.djangoproject.com/ja/4.2/ref/templates/builtins/#ref-templates-builtins-filters • フィルターと違って、独立した処理、機能を提供する。パラメータには文 字列や変数を指定できる。 • タグ: {% タグ名 パラメータ1 パラメータ2 ... %}
タグによる制御構文: if else endif • テンプレート内で条件分岐を利用できる。 >>> template = django_engine.from_string(
... "{% if value >= 5 %}{{ value }}は5以上{% else %}{{ value }}は5未満{% endif %}" ... ) >>> template.render({"value": 7}) '7は5以上' >>> template.render({"value": 3}) '3は5未満'
タグによる制御構文: for endfor • テンプレート内で繰り返し制御を利用できる。 >>> template = django_engine.from_string("{% for
x in data %}{{ x }}{% endfor %}") >>> template.render({"data": range(5)}) '01234'
タグによる構造化(1): include • 指定したテンプレートファイルを取り込む。 {% include "spam/egg.html" %}
タグによる構造化(2): extends block endblock • テンプレートの継承構造を作れる。 • 継承元のテンプレートでは、blockタグで変更可能なブロック を定義する •
継承したテンプレートでは、blockタグで変更したい部分だけ を定義する
Hello {% block name %}{% endblock %}! base.html {% extends
"base.html" %} {% block name %}bar{% endblock %} bar.html {% extends "base.html" %} {% block name %}foo{% endblock %} foo.html >>> from django.template import loader >>> template = loader.get_template("foo.html") >>> template.render() 'Hello foo!¥n' >>> template = loader.get_template("bar.html") >>> template.render() 'Hello bar!¥n'
Djangoテンプレートをどういうときに使う? • HTML生成のテンプレートとして • メール文章のテンプレートとして • テキスト形式のファイルを生成するテンプレートとして • ユーザーに表示するメッセージのテンプレートとして •
「文字列生成のときに使える」ということを覚えておくとよい
静的ファイルの取り扱い: staticタグ • staticタグを使うと、django.contrib.staticfilesで配信されるファイルのパスを生成できる {% load "static" %} <img src="{%
static "spam/egg.jpg" %}"> • 基本的に、静的ファイルのパスの指定はstaticタグを使う、と考えておけばよい。
リンクのパス生成: urlタグ urlpatterns = [ path("foo/bar/", views.MyView.as_view(), name="my_view"), ] urls.py
• urlタグを使うと、urls.pyで定義したViewのパスを生成できる <a href="{% url "my_view" %}">リンク</a> link.html
コンテキストプロセッサ • 汎用のコンテキストを供給する機能。 • レンダリング時の関数やメソッドにコンテキストを渡さなくて も、テンプレート内でコンテキストプロセッサのコンテキスト を利用できる
コンテキストプロセッサの設定 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], #
任意のテンプレートディレクトリ追加 'APP_DIRS': True, # アプリのtemplatesを使うか 'OPTIONS': { 'context_processors': [ # コンテキストプロセッサ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] settings.py
コンテキストプロセッサ: debug • 追加で使えるコンテキスト • debug: デバッグモードが有効かどうか • settings.DEBUG=Trueかつ、REMOTE_ADDRがINTERNAL_IPSに含まれている ものかどうか
• sql_queries: このテンプレートがレンダリングされるまでに実行され たSQLログ
コンテキストプロセッサ: request • 追加で使えるコンテキスト • request: Djangoのrequestオブジェクト(django.http.HttpRequest)
コンテキストプロセッサ: auth • django.contrib.authの機能。認証、権限。 • 追加で使えるコンテキスト • user: ログイン中のユーザー auth.Userまたは、未ログインの場合は
AnonymousUser • perms: 現在ログイン中のユーザーが有するパーミッション
コンテキストプロセッサ: messages • django.contrib.messages(メッセージフレームワーク)の機 能 • 追加で使えるコンテキスト • messages: メッセージフレームワークでセットされたメッセージ一覧。
• DEFAULT_MESSAGE_LEVELS: メッセージレベル名の数値
テンプレートエンジンの カスタマイズ
テンプレートエンジンのカスタマイズポ イント • 自作できるもの • フィルター • タグ • コンテキストプロセッサ
• テンプレートローダー • そもそもテンプレートエンジン自体を差し替えできる • これをやると何でもアリになるのが、ここでは解説しない
フィルターとタグをカスタマイズする準備 • アプリのディレクトリに templatetags という名前のディレクトリを作成 templatetags |--- __init__.py |--- my_customs.py
• 今回は my_customs という名前のモジュールに、カスタムのフィルターとタグを作成す る。 • テンプレート内で有効化するときは、 load タグでロードする。 {% load my_customs %} https://docs.djangoproject.com/ja/4.2/howto/custom-template-tags/
カスタマイズ: フィルター from django import template register = template.Library() @register.filter(name="cut")
def cut(value, arg): return value.replace(arg, "") my_customs.py https://docs.djangoproject.com/ja/4.2/howto/custom-template-tags/#writing-custom-template- filters
カスタマイズ: タグ from django import template register = template.Library() @register.simple_tag
def random_choice(): return value.replace(arg, "") my_customs.py https://docs.djangoproject.com/ja/4.2/howto/custom-template-tags/#writing-custom-template- filters
カスタマイズ: コンテキストプロセッサ • たくさんのページで使う可能性のあるコンテキストを追加した いときに利用 • 注意: コンテキストプロセッサは、テンプレートのレンダリン グ時に毎回実行されるので、遅い処理を入れると全体的に遅く なるかも
• 部分的に使いたいだけであれば、テンプレートタグで十分な場 合が多い
コンテキストプロセッサの作成 import sys def python_version(request): return {'python_version': sys.version} myapp/context_processors.py •
{{ python_version }} のように使える
コンテキストプロセッサの有効化 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS':
True, 'OPTIONS': { 'context_processors': [ ..., # 省略 'myapp.context_processors.python_version', ], }, }, ] settings.py
コンテキストプロセッサの変数を使って みる {{ python_version }} python_version.html
テンプレートローダーについて知る • Djangoテンプレートエンジンが、どこからテンプレートデータ をロードしてくるかを制御する • 組み込みのローダー • django.template.loaders.filesystem: ファイル •
django.template.loaders.app_directories: アプリのtemplatesディレクトリ • django.template.loaders.locmem: ローカルメモリ • django.template.loaders.cached: キャッシュ機能付きローダー https://docs.djangoproject.com/en/4.2/ref/templates/api/#loader-types
テンプレートローダーの設定 TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "OPTIONS": { "loaders":
[ ( "django.template.loaders.filesystem.Loader", [BASE_DIR / "templates"], ), ], }, } ] settings.py
カスタマイズ: テンプレートローダー • 例. データベースからテンプレートをロードする、テンプレー トローダーを自作してみる。 from django.db import models
class Template(models.Model): name = models.CharField(max_length=255) source = models.TextField() myapp/models.py
from django.template.loaders.base import Loader as BaseLoader from django.template import Origin
from .models import Template class DatabaseOrigin(Origin): def __init__(self, name, template_name=None, loader=None, object=None): super().__init__(name, template_name, loader) self.object = object class Loader(BaseLoader): def get_contents(self, origin): return origin.object.source def get_template_sources(self, template_name): template = Template.objects.filter(name=template_name).first() if not template: return [] origin = DatabaseOrigin( name=template_name, template_name=template_name, loader=self, object=template) return [origin] myapp/db_loader.py
テンプレートローダーの設定 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'context_processors':
[ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], 'loaders': [ (‘myapp.db_loader.Loader’,), # ここを追加 ( ‘django.template.loaders.app_directories.Loader’,), # Django adminなどが動くように ] } }, ] settings.py
None
None
まとめ • Djangoテンプレートエンジンは文字列生成に使う • テンプレートとコンテキストを組み合わせてレンダリングする • テンプレート言語で制御できる • 機能をカスタマイズできる
Django利用状況アンケート実施中! • Googleフォームから回答をお願いします。 • 回答受付期間:2023/10/2(月) ~ 2023/10/16(月) • https://forms.gle/ykQcgtHpWjpods348
ありがとうございました!