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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
徹底討論!ECS vs EKS!
daitak
3
1.8k
Agile and AI Redmine Japan 2026
hiranabe
4
500
起点・思考・出力で分解する 〜PM業務の自動化設計〜
kazu_kichi_67
2
1.1k
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
300
When Platform Engineering Meets GenAI
sucitw
0
200
AI-DLCを “そのまま導入しなかった”話 ~組織に合わせてアジャストした 私たちの実践共有~
hiroramos4
PRO
1
450
Why is RC4 still being used?
tamaiyutaro
0
170
Hatena Engineer Seminar 37 jj1uzh
jj1uzh
0
180
4人目のSREはAgent
tanimuyk
0
280
コミュニティの有益性 ~JAWS Days 2026 での体験を通して~ / The Benefits of a Community ~Through My Experience at JAWS Days 2026~
seike460
PRO
0
300
Multi-Agent並列開発を 安全に回すための技術 / Technology for Safely Multi-Agent Parallel Development
tooppoo
0
220
テスト設計の本質を改めて考えてみる~生成AIを活用する時代だからこそ、作ったテストの説明性を高めよう~
yamasaki696
1
150
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
A better future with KSS
kneath
240
18k
Raft: Consensus for Rubyists
vanstee
141
7.6k
WCS-LA-2024
lcolladotor
0
660
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
Everyday Curiosity
cassininazir
0
240
We Are The Robots
honzajavorek
0
260
How Software Deployment tools have changed in the past 20 years
geshan
0
34k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
150
The Curious Case for Waylosing
cassininazir
1
410
Docker and Python
trallard
47
3.9k
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
ありがとうございました!