ExprTag - Calculating python expression and saving the result to a variable

 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
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)

More like this

  1. CallTag - Just like include, but can pass parameters to it by limodou 7 years, 1 month ago
  2. CatchTag - Catching the content and saving it to a variable by limodou 7 years, 1 month ago
  3. Switch template tag by adurdin 5 years, 8 months ago
  4. PyCallTag - Directly call python function or attribute of a module by limodou 7 years, 1 month ago
  5. math tag by itchyfingrs 2 years, 11 months ago

Comments

kunitoki (on June 9, 2010):

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:

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:
                for item in c:
                    if isinstance(item, dict): 
                        d.update(item)
            if self.var_name:
                context[self.var_name] = eval(self.expr_string, d)
                return ''
            else:
                return str(eval(self.expr_string, d))
        except:
            raise

#

sjohnson (on December 15, 2011):

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)

#

(Forgotten your password?)