1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 | import re
from shlex import split
from django.utils.importlib import import_module
from django import template
from django.conf import settings
from django.template.loader import get_template
from django.template.context import Context
from template_utils import functions
def import_function(s):
"""
Import a function given the string formatted as
`module_name.function_name` (eg `django.utils.text.capfirst`)
"""
a = s.split('.')
j = lambda x: '.'.join(x)
return getattr(import_module(j(a[:-1])), a[-1])
class FunctionalNode(template.Node):
def __init__(self, func, varname=None, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
self.varname = varname
def render(self, context):
def lookup(var, resolve=True):
if resolve:
var = template.Variable(var)
try:
return var.resolve(context)
except template.VariableDoesNotExist:
return unicode(var)
return unicode(var)
func = functions[self.func]
resolve = not (hasattr(func, 'do_not_resolve') and getattr(func, 'do_not_resolve'))
args = [lookup(var, resolve) for var in self.args]
kwargs = dict([(k, lookup(var, resolve)) for k,var in self.kwargs.items()])
if isinstance(func, basestring):
func = import_function(func)
if hasattr(func,'takes_context') and getattr(func, 'takes_context'):
args = [context] + args
if hasattr(func, 'is_inclusion') and getattr(func, 'is_inclusion'):
template_name,ctx = func(*args, **kwargs)
if not isinstance(ctx, Context):
ctx = Context(ctx)
result = get_template(template_name).render(ctx)
else:
result = func(*args, **kwargs)
if self.varname:
context[self.varname] = result
return ''
return result
def do_function(parser, token):
"""
Performs a defined function an either outputs results, or stores results in template variable
Syntax::
{% [function] [var args...] [name=value kwargs...] [as varname] %}
Examples::
{% listdir '.' colors=True %}
"""
varname = None
bits = [filter(lambda x: x != '\x00', token) for token in split(' '.join(token.contents.split()))]
if len(bits) > 2 and bits[-2] == 'as':
varname = bits[-1]
bits = bits[:-2]
kwarg_re = re.compile(r'(^[A-z]+)\=(.+)')
args, kwargs = (),{}
for bit in bits[1:]:
match = kwarg_re.match(bit)
if match:
kwargs[match.group(1)] = match.group(2)
else:
args += (bit,)
return FunctionalNode(bits[0], varname, *args, **kwargs)
register = template.Library()
for tag_name in functions:
register.tag(tag_name, do_function)
|