Call Tag
- version: 0.2
- author: limodou@gmail.com
Updates
- 2006/12/03 Change do_include to do_call, etc, and some import usage.
I knew that template in myght template system can receive some parameters just like a function. And I also want to implement this function in django template. So I finish a rough one, the code is pasted here. It just like include, but in order to distinguish with "include" tag, I call it "call". So you can use it:
{% call "some.html" %}
This way just like include tag, and the advanced way:
{% call "some.html" with "a" "b"|capfirst title="title1" %}
{% call "some.html" with "c" "d" title="title2" %}
So you can see, "call" tag can do like a python function, it can receive tuple parameters and key word parameters, just like the function:
def func(*args, **kwargs):pass
Code
from django import template
from django.template.loader import get_template
from django.conf import settings
import tokenize
import StringIO
register = template.Library()
class CallNode(template.Node):
def __init__(self, template_name, *args, **kwargs):
self.template_name = template_name
self.args = args
self.kwargs = kwargs
def render(self, context):
try:
template_name = self.template_name.resolve(context)
t = get_template(template_name)
d = {}
args = d['args'] = []
kwargs = d['kwargs'] = {}
for i in self.args:
args.append(i.resolve(context))
for key, value in self.kwargs.items():
kwargs[key] = d[key] = value.resolve(context)
context.update(d)
result = t.render(context)
context.pop()
return result
except:
if settings.TEMPLATE_DEBUG:
raise
return ''
def do_call(parser, token):
"""
Loads a template and renders it with the current context.
Example::
{% call "foo/some_include" %}
{% call "foo/some_include" with arg1 arg2 ... argn %}
"""
bits = token.contents.split()
if 'with' in bits: #has 'with' key
pos = bits.index('with')
argslist = bits[pos+1:]
bits = bits[:pos]
else:
argslist = []
if len(bits) != 2:
raise template.TemplateSyntaxError, "%r tag takes one argument: the name of the template to be included" % bits[0]
path = parser.compile_filter(bits[1])
if argslist:
args = []
kwargs = {}
for i in argslist:
if '=' in i:
a, b = i.split('=', 1)
a = a.strip()
b = b.strip()
buf = StringIO.StringIO(a)
keys = list(tokenize.generate_tokens(buf.readline))
if keys[0][0] == tokenize.NAME:
kwargs[a] = parser.compile_filter(b)
else:
raise template.TemplateSyntaxError, "Argument syntax wrong: should be key=value"
else:
args.append(parser.compile_filter(i))
return CallNode(path, *args, **kwargs)
register.tag('call', do_call)
How to use it
test_call.html
{% expr "limodou" as name %}
{% call "test/test_sub.html" with "a"|capfirst "b" title="title1" %}<br/>
{% call "test/test_sub.html" with "c" "d" title="title2" %}
expr is also a custom tag written by me. It'll calculate a python expression and save to result to a variable. In this case, the variable it "name".
test_sub.html
{% for i in args %}{{ i }}{% endfor %}
<h2>{{ title }}</h2>
<p>{{ name }}</p>
<h3>args</h3>
{{ args }}
<h3>kwargs</h3>
{{ kwargs }}
And you also can see, call tag will auto create args and kwargs context variables.
I hope this will be some useful.
