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 ago
  2. Parsing Tag decorator by pgcd 3 years ago
  3. Image model with thumbnail by clawlor 2 years, 10 months ago
  4. Django Breadcrumbs Snippet by flashingpumpkin 4 years ago
  5. Passing values to a method from a template by miracle2k 5 years, 2 months ago

Comments

showell (on May 5, 2009):

Nice!

Folks who like this may also want smart if.

#

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