Login

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

Author:
limodou
Posted:
February 25, 2007
Language:
Python
Version:
Pre .96
Tags:
tag
Score:
17 (after 17 ratings)

This tag can be used to calculate a python expression, and save it into a template variable which you can reuse later or directly output to template. So if the default django tag can not be suit for your need, you can use it.

How to use it

{% expr "1" as var1 %}
{% expr [0, 1, 2] as var2 %}
{% expr _('Menu') as var3 %}
{% expr var1 + "abc" as var4 %}
...
{{ var1 }}

for 0.2 version

{% expr 3 %}
{% expr "".join(["a", "b", "c"]) %}

Will directly output the result to template

Syntax

{% expr python_expression as variable_name %}

python_expression can be valid python expression, and you can even use _() to translate a string. Expr tag also can used context variables.

 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 8 years, 1 month ago
  2. CatchTag - Catching the content and saving it to a variable by limodou 8 years, 1 month ago
  3. Switch template tag by adurdin 6 years, 7 months ago
  4. PyCallTag - Directly call python function or attribute of a module by limodou 8 years, 1 month ago
  5. math tag by itchyfingrs 3 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)

#

Please login first before commenting.