Login

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

Author:
limodou
Posted:
February 25, 2007
Language:
Python
Version:
Pre .96
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. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 11 months, 3 weeks 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.