Login

if tag with method call

Author:
dahool
Posted:
May 5, 2009
Language:
Python
Version:
1.0
Score:
2 (after 2 ratings)

This tag will invoke the specified method with the passed arguments.

 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. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 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.

#

Please login first before commenting.