if tag with method call

 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
def iftrue(parser, token):
    '''
    call the given method with the specified arguments.
    
        {% iftrue object.method arg, ... %}
            ....
        {% else %}
            ....
        {% endiftrue %}
        
        {% iftrue object.method arg1=arg1,arg2=arg2 ... %}
            ....
    '''
    
    bits = list(token.split_contents())
    if len(bits) < 2:
        raise TemplateSyntaxError, "%r takes at least two arguments" % bits[0]
    end_tag = 'end' + bits[0]
    nodelist_true = parser.parse(('else', end_tag))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse((end_tag,))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
        
    object = bits[1]
    args = []
    kwargs = {}
        
    bits = iter(bits[2:])
    for bit in bits:
        for arg in bit.split(","):
            if '=' in arg:
                k, v = arg.split('=', 1)
                k = k.strip()
                kwargs[k] = parser.compile_filter(v)
            elif arg:
                args.append(parser.compile_filter(arg))
                                
    return IfTrueNode(object, args, kwargs, nodelist_true, nodelist_false)
iftrue = register.tag(iftrue)

class IfTrueNode(Node):
    def __init__(self, object, args, kwargs, nodelist_true, nodelist_false):
        self.object, self.args, self.kwargs = object, args, kwargs
        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false

    def __repr__(self):
        return "<IfTrueNode>"

    def render(self, context):
        args = [arg.resolve(context) for arg in self.args]
        kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
                       for k, v in self.kwargs.items()])
                
        obj_p = self.object.split('.')
        object = '.'.join(obj_p[:-1])
        method = ''.join(obj_p[-1:])
        obj = resolve_variable(object,context)
        func = getattr(obj,method)
        
        if func(*args, **kwargs):
            return self.nodelist_true.render(context)
        else:
            return self.nodelist_false.render(context)

More like this

  1. a template tag to invoke a method on an object with a variable by Scanner 6 years, 11 months ago
  2. invoke pyflakes via manage.py by mpasternacki 4 years, 6 months ago
  3. Functional Filters by waterson 6 years, 7 months ago
  4. Case-insensitive lookup by default by sciyoshi 6 years, 9 months ago
  5. testdata tag for templates by showell 4 years, 11 months ago

Comments

michal.przywara (on August 18, 2009):

This is cool; needed in core, I'd even say. It seems to be a staple of other templating systems, and separation of concerns aside, there's no shortage of uses for evaluating an "if" function that only affects the UI in the template itself. It took me a while to track down all of the imports for this, but while doing so I noticed that "resolve_variable" is deprecated (line 60). Locally I replaced it with obj = Variable(object).resolve(context) (where "Variable" is from django.templates), and it works as well, though I don't know if its better or worse yet.

#

(Forgotten your password?)