Ticket #10821: if_in_list_tag.py

File if_in_list_tag.py, 2.8 KB (added by tomevans222, 15 years ago)

Implementation of IfInList tag

Line 
1# This tag library adds a useful tag for checking whether an element is in a list of not
2# This can be useful if iterating over a list of all values, and testing to see if it is
3# in our current collection. It behaves like a usual 'if' and can be accompanied by an
4# 'else' block as well.
5#
6# EG:
7# ctxt = { 'my_colours': ['orange', 'yellow'],
8# 'all_colours': ['red', 'orange', 'yellow', 'green', blue', 'indigo', 'violet'] }
9# <tr>{% for clr in all_colours %}<th>{{ clr }}</th>{% endfor %}</tr>
10# <tr>
11# {% for clr in all_colours %}
12# <td>{% IfInList clr in my_colours %}I like it{% else %}I hate it{% endif %}</td>
13# {% endfor %}
14# </tr>
15#
16# You can also negate the test:
17#
18# <td>{% IfInList clr not in mine %}</td>
19#
20from django.template import Node, Variable, TemplateSyntaxError, Library, NodeList, VariableDoesNotExist
21
22register = Library()
23
24class IfInListNode(Node):
25 def __init__(self, obj, list, nodelist_true, nodelist_false, negate):
26 self.obj, self.list = Variable(obj), list
27 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
28 self.negate = negate
29
30 def __repr__(self):
31 return '<IfInList node>'
32
33 def __iter__(self):
34 for node in self.nodelist_true:
35 yield node
36 for node in self.nodelist_false:
37 yield node
38
39 def get_nodes_by_type(self, nodetype):
40 nodes = []
41 if isinstance(self, nodetype):
42 nodes.append(self)
43 nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
44 nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
45 return nodes
46
47 def render(self, context):
48 try:
49 val = self.obj.resolve(context)
50 except VariableDoesNotExist:
51 val = None
52 try:
53 list = self.list.resolve(context, True)
54 except VariableDoesNotExist:
55 list = []
56 in_list = val in list
57 if in_list and not self.negate or self.negate and not in_list:
58 return self.nodelist_true.render(context)
59 else:
60 return self.nodelist_false.render(context)
61
62
63@register.tag(name='IfInList')
64def do_if_in_list(parser, token):
65 bits = token.contents.split()
66 tag_name, var_not, var_in = None, None, None
67 if len(bits) == 4:
68 tag_name, obj, var_in, list = token.split_contents()
69 elif len(bits) == 5:
70 tag_name, obj, var_not, var_in, list = token.split_contents()
71 if not tag_name \
72 or (var_not is not None and var_not != 'not') \
73 or (var_in is not None and var_in != 'in'):
74 raise TemplateSyntaxError("Invalid format! 'IfInList obj [not] in list'. You had: %s" % token.contents)
75 negate = var_not is not None
76 list = parser.compile_filter(list)
77 nodelist_true = parser.parse(('else', 'endif'))
78 tok = parser.next_token()
79 if tok.contents == 'else':
80 nodelist_false = parser.parse(('endif',))
81 parser.delete_first_token()
82 else:
83 nodelist_false = NodeList()
84 return IfInListNode(obj, list, nodelist_true, nodelist_false, negate)
Back to Top