9. {% with %} タグ
• テンプレート中で変数を束縛する
• ブロック内がスコープ
• スコープ内の {% include %} に波及
する
• ネスト可
{% with a='foo' b='bar' %}
!
Outside nest:{{ a }}/{{ b }}/{{ c }}.
!
{% with c=a b='baz' %}
!
Inside nest: {{ a }}/{{ b }}/{{ c }}.
!
{% endwith %}
!
{% endwith %}
!
Outside nest: foo/bar/.
!
Inside nest: foo/baz/foo.
10. {% with %} の構文
{% with a=123 c='defg' e=hij ... %}
タグ トークン列
トークン トークン トークン
a=123
a as 123
古い形式の
キーワード引数
キーワード引数
キー 引数
11. {% with %} の実装(1)
@register.tag('with')
def do_with(parser, token):
...
bits = token.split_contents()
remaining_bits = bits[1:]
extra_context = token_kwargs(remaining_bits, parser, support_legacy=True)
if not extra_context:
raise TemplateSyntaxError("%r expected at least one variable "
"assignment" % bits[0])
if remaining_bits:
raise TemplateSyntaxError("%r received an invalid token: %r" %
(bits[0], remaining_bits[0]))
nodelist = parser.parse(('endwith',))
parser.delete_first_token()
return WithNode(None, None, nodelist, extra_context=extra_context)
トークン列を取り出す
テンプレートの解析中に with タグを見つけたときの処理
各トークンをキーワード引数
として解析する
レンダリングノードを作成する
endwith までを子ノードにする
12. {% with %} の実装(2)
class WithNode(Node):
def __init__(self, var, name, nodelist, extra_context=None):
self.nodelist = nodelist
# var and name are legacy attributes, being left in case they are used
# by third-party subclasses of this Node.
self.extra_context = extra_context or {}
if name:
self.extra_context[name] = var
!
def __repr__(self):
return "<WithNode>"
!
def render(self, context):
values = dict([(key, val.resolve(context)) for key, val in
six.iteritems(self.extra_context)])
context.update(values)
output = self.nodelist.render(context)
context.pop()
return output
子ノード(ブロックの内容)
キーワード引数
互換性用のコード
キーワード引数の値を解決して辞書にする
子ノードをレンダリング
コンテキストをスタック
コンテキストを復帰