from django import template
from django.utils.translation import gettext_lazy as _
import re
register = template.Library()
class ExprNode(template.Node):
def __init__(self, expr_string, var_name):
self.expr_string = expr_string
self.var_name = var_name
def render(self, context):
try:
clist = list(context)
clist.reverse()
d = {}
d['_'] = _
for c in clist:
d.update(c)
if self.var_name:
context[self.var_name] = eval(self.expr_string, d)
return ''
else:
return str(eval(self.expr_string, d))
except:
raise
r_expr = re.compile(r'(.*?)\s+as\s+(\w+)', re.DOTALL)
def do_expr(parser, token):
try:
tag_name, arg = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents[0]
m = r_expr.search(arg)
if m:
expr_string, var_name = m.groups()
else:
if not arg:
raise template.TemplateSyntaxError, "%r tag at least require one argument" % tag_name
expr_string, var_name = arg, None
return ExprNode(expr_string, var_name)
do_expr = register.tag('expr', do_expr)
Comments
This doesn't work inside template blocks in inherited templates (will give errors in dict.update). This update in the node will work on both places:
#
To use the value outside of the block (e.g., outside of the for loop) in which it is set, use
context.dicts[0][self.varname] = eval(self.expr_string, d)
(You could reconfigure the regex to check for "as global" or "as" and set the variable appropriately)
#