Django/テンプレートシステムを読む(読み込みまで)
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Djangoを読む]]
#contents
*はじめに [#gdef0168]
ここまでビュー(一般的なMVCではController)、モデルと見て...
チュートリアルを読んでいくとテンプレートを利用したHTMLコ...
polls/templates/polls/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ quest...
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
ちなみに、このHTMLには<html>とか<body>がありませんが、別...
テンプレートを利用するビュー関数
polls/views.py
#code(Python){{
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pu...
context = {'latest_question_list': latest_question_li...
return render(request, 'polls/index.html', context)
}}
後、テンプレートはsettings.pyのTEMPLATESを参照しているら...
#code(Python){{
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.Djang...
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.reque...
'django.contrib.auth.context_processors.a...
'django.contrib.messages.context_processo...
],
},
},
]
}}
それでは見ていきましょう。
*django/template/loader.py [#v7413407]
スタートはdjango.shortcutsのrender関数ですがチュートリア...
#code(Python){{
from django.template import loader
def render(request, template_name, context=None, content_...
"""
Returns a HttpResponse whose content is filled with t...
django.template.loader.render_to_string() with the pa...
"""
content = loader.render_to_string(template_name, cont...
return HttpResponse(content, content_type, status)
}}
loaderに進む。
#code(Python){{
def render_to_string(template_name, context=None, request...
"""
Loads a template and renders it with a context. Retur...
template_name may be a string or a list of strings.
"""
if isinstance(template_name, (list, tuple)):
template = select_template(template_name, using=u...
else:
template = get_template(template_name, using=using)
return template.render(context, request)
}}
ここまではrender関数使わない版で書かれている内容、ここか...
**django.template.get_template [#y62b519c]
get_template関数。
#code(Python){{
def get_template(template_name, using=None):
"""
Loads and returns a template for the given name.
Raises TemplateDoesNotExist if no such template exists.
"""
chain = []
engines = _engine_list(using)
for engine in engines:
try:
return engine.get_template(template_name)
except TemplateDoesNotExist as e:
chain.append(e)
raise TemplateDoesNotExist(template_name, chain=chain)
}}
_engine_list関数。usingはNoneなのでallが呼び出されます。
#code(Python){{
from . import engines
def _engine_list(using=None):
return engines.all() if using is None else [engines[u...
}}
***django.template.engines [#gbd51587]
enginesは「.」からインポートされているので次に見る先は__i...
#code(Python){{
from .utils import EngineHandler
engines = EngineHandler()
}}
なかなかしつこい(笑)。utils.pyに行きます。
#code(Python){{
class EngineHandler(object):
def __init__(self, templates=None):
"""
templates is an optional list of template engine ...
(structured like settings.TEMPLATES).
"""
self._templates = templates
self._engines = {}
}}
ふうむ。allメソッドを見てみましょう。
#code(Python){{
def all(self):
return [self[alias] for alias in self]
}}
in self、inで書かれているのですぐ上の__iter__が呼ばれると...
#code(Python){{
def __iter__(self):
return iter(self.templates)
}}
さらにtemplates。こいつはプロパティです。一部省略して貼り...
#code(Python){{
@cached_property
def templates(self):
if self._templates is None:
self._templates = settings.TEMPLATES
templates = OrderedDict()
backend_names = []
for tpl in self._templates:
tpl = tpl.copy()
try:
# This will raise an exception if 'BACKEN...
# isn't a string containing at least one ...
default_name = tpl['BACKEND'].rsplit('.',...
except Exception:
# 省略
tpl.setdefault('NAME', default_name)
tpl.setdefault('DIRS', [])
tpl.setdefault('APP_DIRS', False)
tpl.setdefault('OPTIONS', {})
templates[tpl['NAME']] = tpl
backend_names.append(tpl['NAME'])
return templates
}}
デフォルトの設定ではTEMPLATES指定(リスト)には辞書が一つ...
rsplitは紛らわしいですが、第2引数の「2」は「最大2回分割(...
['django.template.backends', 'django', 'DjangoTemplates']
と分割され、[-2]なのですなわちNAMEは'django'です。
というわけで戻ると、
#code(Python){{
def __iter__(self):
return iter(self.templates)
def all(self):
return [self[alias] for alias in self]
}}
self.templatesがOrderedDictなのでイテレータはキーというこ...
#code(Python){{
def __getitem__(self, alias):
try:
return self._engines[alias]
except KeyError:
try:
params = self.templates[alias]
except KeyError:
# 省略
# If importing or initializing the backend ra...
# self._engines[alias] isn't set and this cod...
# again, so we must preserve the original par...
params = params.copy()
backend = params.pop('BACKEND')
engine_cls = import_string(backend)
engine = engine_cls(params)
self._engines[alias] = engine
return engine
}}
一回目は_enginesには何も入っていないのでKeyErrorになりま...
というわけでBACKENDとして書かれているエンジンがインポート...
**django/template/engine.py [#v08cb7f2]
さて、というわけでengine、具体的にはDjangoTemplatesオブジ...
#code(Python){{
def get_template(self, template_name):
try:
return Template(self.engine.get_template(temp...
except TemplateDoesNotExist as exc:
reraise(exc, self)
}}
ややこしいですが、self.engineはdjango.template.engineモジ...
#code(Python){{
def get_template(self, template_name):
"""
Returns a compiled Template object for the given ...
handling template inheritance recursively.
"""
template, origin = self.find_template(template_na...
if not hasattr(template, 'render'):
# template needs to be compiled
template = Template(template, origin, templat...
return template
}}
とりあえずfind_templateに進みましょう。
#code(Python){{
def find_template(self, name, dirs=None, skip=None):
tried = []
for loader in self.template_loaders:
if loader.supports_recursion:
try:
template = loader.get_template(
name, template_dirs=dirs, skip=sk...
)
return template, template.origin
except TemplateDoesNotExist as e:
tried.extend(e.tried)
else:
# RemovedInDjango20Warning: Use old api f...
# loaders.
try:
return loader(name, dirs)
except TemplateDoesNotExist:
pass
raise TemplateDoesNotExist(name, tried=tried)
}}
template_loadersプロパティ
#code(Python){{
@cached_property
def template_loaders(self):
return self.get_template_loaders(self.loaders)
}}
loadersを確認。__init__メソッドに書いてあります。get_temp...
#code(Python){{
if loaders is None:
loaders = ['django.template.loaders.filesyste...
if app_dirs:
loaders += ['django.template.loaders.app_...
}}
***django.template.loaders [#y0aa1341]
今回使用しているテンプレート的にapp_directoriesのLoaderが...
#code(Python){{
from .filesystem import Loader as FilesystemLoader
class Loader(FilesystemLoader):
}}
さかのぼる。
#code(Python){{
from .base import Loader as BaseLoader
class Loader(BaseLoader):
}}
baseまで来るとget_templateが書かれています。
#code(Python){{
def get_template(self, template_name, template_dirs=N...
"""
Calls self.get_template_sources() and returns a T...
the first template matching template_name. If ski...
template origins in skip are ignored. This is use...
during template extending.
"""
tried = []
args = [template_name]
# RemovedInDjango20Warning: Add template_dirs for...
# old loaders
if func_supports_parameter(self.get_template_sour...
args.append(template_dirs)
for origin in self.get_template_sources(*args):
if skip is not None and origin in skip:
tried.append((origin, 'Skipped'))
continue
try:
contents = self.get_contents(origin)
except TemplateDoesNotExist:
tried.append((origin, 'Source does not ex...
continue
else:
return Template(
contents, origin, origin.template_nam...
)
raise TemplateDoesNotExist(template_name, tried=t...
}}
get_template_sources、get_contentsはいずれもサブクラスのf...
#code(Python){{
def get_template_sources(self, template_name, templat...
"""
Return an Origin object pointing to an absolute p...
in template_dirs. For security reasons, if a path...
one of the template_dirs it is excluded from the ...
"""
if not template_dirs:
template_dirs = self.get_dirs()
for template_dir in template_dirs:
try:
name = safe_join(template_dir, template_n...
except SuspiciousFileOperation:
# The joined path was located outside of ...
# (it might be inside another one, so thi...
continue
yield Origin(
name=name,
template_name=template_name,
loader=self,
)
}}
get_dirsメソッドはapp_directoriesのLoaderではオーバーライ...
#code(Python){{
def get_dirs(self):
return get_app_template_dirs('templates')
}}
結果、テンプレートのファイルが読み込まれ、コンパイルが行...
*おわりに [#t93b2228]
今回はDjangoのテンプレートシステム、とりあえず指定されて...
感想としては、いろいろなところで同じ名前を使っているな、t...
終了行:
[[Djangoを読む]]
#contents
*はじめに [#gdef0168]
ここまでビュー(一般的なMVCではController)、モデルと見て...
チュートリアルを読んでいくとテンプレートを利用したHTMLコ...
polls/templates/polls/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ quest...
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
ちなみに、このHTMLには<html>とか<body>がありませんが、別...
テンプレートを利用するビュー関数
polls/views.py
#code(Python){{
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pu...
context = {'latest_question_list': latest_question_li...
return render(request, 'polls/index.html', context)
}}
後、テンプレートはsettings.pyのTEMPLATESを参照しているら...
#code(Python){{
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.Djang...
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.reque...
'django.contrib.auth.context_processors.a...
'django.contrib.messages.context_processo...
],
},
},
]
}}
それでは見ていきましょう。
*django/template/loader.py [#v7413407]
スタートはdjango.shortcutsのrender関数ですがチュートリア...
#code(Python){{
from django.template import loader
def render(request, template_name, context=None, content_...
"""
Returns a HttpResponse whose content is filled with t...
django.template.loader.render_to_string() with the pa...
"""
content = loader.render_to_string(template_name, cont...
return HttpResponse(content, content_type, status)
}}
loaderに進む。
#code(Python){{
def render_to_string(template_name, context=None, request...
"""
Loads a template and renders it with a context. Retur...
template_name may be a string or a list of strings.
"""
if isinstance(template_name, (list, tuple)):
template = select_template(template_name, using=u...
else:
template = get_template(template_name, using=using)
return template.render(context, request)
}}
ここまではrender関数使わない版で書かれている内容、ここか...
**django.template.get_template [#y62b519c]
get_template関数。
#code(Python){{
def get_template(template_name, using=None):
"""
Loads and returns a template for the given name.
Raises TemplateDoesNotExist if no such template exists.
"""
chain = []
engines = _engine_list(using)
for engine in engines:
try:
return engine.get_template(template_name)
except TemplateDoesNotExist as e:
chain.append(e)
raise TemplateDoesNotExist(template_name, chain=chain)
}}
_engine_list関数。usingはNoneなのでallが呼び出されます。
#code(Python){{
from . import engines
def _engine_list(using=None):
return engines.all() if using is None else [engines[u...
}}
***django.template.engines [#gbd51587]
enginesは「.」からインポートされているので次に見る先は__i...
#code(Python){{
from .utils import EngineHandler
engines = EngineHandler()
}}
なかなかしつこい(笑)。utils.pyに行きます。
#code(Python){{
class EngineHandler(object):
def __init__(self, templates=None):
"""
templates is an optional list of template engine ...
(structured like settings.TEMPLATES).
"""
self._templates = templates
self._engines = {}
}}
ふうむ。allメソッドを見てみましょう。
#code(Python){{
def all(self):
return [self[alias] for alias in self]
}}
in self、inで書かれているのですぐ上の__iter__が呼ばれると...
#code(Python){{
def __iter__(self):
return iter(self.templates)
}}
さらにtemplates。こいつはプロパティです。一部省略して貼り...
#code(Python){{
@cached_property
def templates(self):
if self._templates is None:
self._templates = settings.TEMPLATES
templates = OrderedDict()
backend_names = []
for tpl in self._templates:
tpl = tpl.copy()
try:
# This will raise an exception if 'BACKEN...
# isn't a string containing at least one ...
default_name = tpl['BACKEND'].rsplit('.',...
except Exception:
# 省略
tpl.setdefault('NAME', default_name)
tpl.setdefault('DIRS', [])
tpl.setdefault('APP_DIRS', False)
tpl.setdefault('OPTIONS', {})
templates[tpl['NAME']] = tpl
backend_names.append(tpl['NAME'])
return templates
}}
デフォルトの設定ではTEMPLATES指定(リスト)には辞書が一つ...
rsplitは紛らわしいですが、第2引数の「2」は「最大2回分割(...
['django.template.backends', 'django', 'DjangoTemplates']
と分割され、[-2]なのですなわちNAMEは'django'です。
というわけで戻ると、
#code(Python){{
def __iter__(self):
return iter(self.templates)
def all(self):
return [self[alias] for alias in self]
}}
self.templatesがOrderedDictなのでイテレータはキーというこ...
#code(Python){{
def __getitem__(self, alias):
try:
return self._engines[alias]
except KeyError:
try:
params = self.templates[alias]
except KeyError:
# 省略
# If importing or initializing the backend ra...
# self._engines[alias] isn't set and this cod...
# again, so we must preserve the original par...
params = params.copy()
backend = params.pop('BACKEND')
engine_cls = import_string(backend)
engine = engine_cls(params)
self._engines[alias] = engine
return engine
}}
一回目は_enginesには何も入っていないのでKeyErrorになりま...
というわけでBACKENDとして書かれているエンジンがインポート...
**django/template/engine.py [#v08cb7f2]
さて、というわけでengine、具体的にはDjangoTemplatesオブジ...
#code(Python){{
def get_template(self, template_name):
try:
return Template(self.engine.get_template(temp...
except TemplateDoesNotExist as exc:
reraise(exc, self)
}}
ややこしいですが、self.engineはdjango.template.engineモジ...
#code(Python){{
def get_template(self, template_name):
"""
Returns a compiled Template object for the given ...
handling template inheritance recursively.
"""
template, origin = self.find_template(template_na...
if not hasattr(template, 'render'):
# template needs to be compiled
template = Template(template, origin, templat...
return template
}}
とりあえずfind_templateに進みましょう。
#code(Python){{
def find_template(self, name, dirs=None, skip=None):
tried = []
for loader in self.template_loaders:
if loader.supports_recursion:
try:
template = loader.get_template(
name, template_dirs=dirs, skip=sk...
)
return template, template.origin
except TemplateDoesNotExist as e:
tried.extend(e.tried)
else:
# RemovedInDjango20Warning: Use old api f...
# loaders.
try:
return loader(name, dirs)
except TemplateDoesNotExist:
pass
raise TemplateDoesNotExist(name, tried=tried)
}}
template_loadersプロパティ
#code(Python){{
@cached_property
def template_loaders(self):
return self.get_template_loaders(self.loaders)
}}
loadersを確認。__init__メソッドに書いてあります。get_temp...
#code(Python){{
if loaders is None:
loaders = ['django.template.loaders.filesyste...
if app_dirs:
loaders += ['django.template.loaders.app_...
}}
***django.template.loaders [#y0aa1341]
今回使用しているテンプレート的にapp_directoriesのLoaderが...
#code(Python){{
from .filesystem import Loader as FilesystemLoader
class Loader(FilesystemLoader):
}}
さかのぼる。
#code(Python){{
from .base import Loader as BaseLoader
class Loader(BaseLoader):
}}
baseまで来るとget_templateが書かれています。
#code(Python){{
def get_template(self, template_name, template_dirs=N...
"""
Calls self.get_template_sources() and returns a T...
the first template matching template_name. If ski...
template origins in skip are ignored. This is use...
during template extending.
"""
tried = []
args = [template_name]
# RemovedInDjango20Warning: Add template_dirs for...
# old loaders
if func_supports_parameter(self.get_template_sour...
args.append(template_dirs)
for origin in self.get_template_sources(*args):
if skip is not None and origin in skip:
tried.append((origin, 'Skipped'))
continue
try:
contents = self.get_contents(origin)
except TemplateDoesNotExist:
tried.append((origin, 'Source does not ex...
continue
else:
return Template(
contents, origin, origin.template_nam...
)
raise TemplateDoesNotExist(template_name, tried=t...
}}
get_template_sources、get_contentsはいずれもサブクラスのf...
#code(Python){{
def get_template_sources(self, template_name, templat...
"""
Return an Origin object pointing to an absolute p...
in template_dirs. For security reasons, if a path...
one of the template_dirs it is excluded from the ...
"""
if not template_dirs:
template_dirs = self.get_dirs()
for template_dir in template_dirs:
try:
name = safe_join(template_dir, template_n...
except SuspiciousFileOperation:
# The joined path was located outside of ...
# (it might be inside another one, so thi...
continue
yield Origin(
name=name,
template_name=template_name,
loader=self,
)
}}
get_dirsメソッドはapp_directoriesのLoaderではオーバーライ...
#code(Python){{
def get_dirs(self):
return get_app_template_dirs('templates')
}}
結果、テンプレートのファイルが読み込まれ、コンパイルが行...
*おわりに [#t93b2228]
今回はDjangoのテンプレートシステム、とりあえず指定されて...
感想としては、いろいろなところで同じ名前を使っているな、t...
ページ名: