Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #256 and #334 -- Added {% ifequal %} template tag. Also, {% ife…

…qual %} and {% ifnotequal %} now both accept an optional {% else %} clause. Unit tests included.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@574 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit d80ac5ac2517d02f9af87d8c8ea46bc376c51bc5 1 parent bcce1d9
Adrian Holovaty authored August 29, 2005
48  django/core/defaulttags.py
@@ -126,18 +126,21 @@ def render(self, context):
126 126
         else:
127 127
             return ''
128 128
 
129  
-class IfNotEqualNode(template.Node):
130  
-    def __init__(self, var1, var2, nodelist):
131  
-        self.var1, self.var2, self.nodelist = var1, var2, nodelist
  129
+class IfEqualNode(template.Node):
  130
+    def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
  131
+        self.var1, self.var2 = var1, var2
  132
+        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
  133
+        self.negate = negate
132 134
 
133 135
     def __repr__(self):
134  
-        return "<IfNotEqualNode>"
  136
+        return "<IfEqualNode>"
135 137
 
136 138
     def render(self, context):
137  
-        if template.resolve_variable(self.var1, context) != template.resolve_variable(self.var2, context):
138  
-            return self.nodelist.render(context)
139  
-        else:
140  
-            return ''
  139
+        val1 = template.resolve_variable(self.var1, context)
  140
+        val2 = template.resolve_variable(self.var2, context)
  141
+        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
  142
+            return self.nodelist_true.render(context)
  143
+        return self.nodelist_false.render(context)
141 144
 
142 145
 class IfNode(template.Node):
143 146
     def __init__(self, boolvars, nodelist_true, nodelist_false):
@@ -449,22 +452,34 @@ def do_for(parser, token):
449 452
     parser.delete_first_token()
450 453
     return ForNode(loopvar, sequence, reversed, nodelist_loop)
451 454
 
452  
-def do_ifnotequal(parser, token):
  455
+def do_ifequal(parser, token, negate):
453 456
     """
454  
-    Output the contents of the block if the two arguments do not equal each other.
  457
+    Output the contents of the block if the two arguments equal/don't equal each other.
455 458
 
456  
-    Example::
  459
+    Examples::
  460
+
  461
+        {% ifequal user.id comment.user_id %}
  462
+            ...
  463
+        {% endifequal %}
457 464
 
458 465
         {% ifnotequal user.id comment.user_id %}
459 466
             ...
  467
+        {% else %}
  468
+            ...
460 469
         {% endifnotequal %}
461 470
     """
462 471
     bits = token.contents.split()
463 472
     if len(bits) != 3:
464  
-        raise template.TemplateSyntaxError, "'ifnotequal' takes two arguments"
465  
-    nodelist = parser.parse(('endifnotequal',))
466  
-    parser.delete_first_token()
467  
-    return IfNotEqualNode(bits[1], bits[2], nodelist)
  473
+        raise template.TemplateSyntaxError, "%r takes two arguments" % bits[0]
  474
+    end_tag = 'end' + bits[0]
  475
+    nodelist_true = parser.parse(('else', end_tag))
  476
+    token = parser.next_token()
  477
+    if token.contents == 'else':
  478
+        nodelist_false = parser.parse((end_tag,))
  479
+        parser.delete_first_token()
  480
+    else:
  481
+        nodelist_false = template.NodeList()
  482
+    return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
468 483
 
469 484
 def do_if(parser, token):
470 485
     """
@@ -736,7 +751,8 @@ def do_widthratio(parser, token):
736 751
 template.register_tag('filter', do_filter)
737 752
 template.register_tag('firstof', do_firstof)
738 753
 template.register_tag('for', do_for)
739  
-template.register_tag('ifnotequal', do_ifnotequal)
  754
+template.register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
  755
+template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
740 756
 template.register_tag('if', do_if)
741 757
 template.register_tag('ifchanged', do_ifchanged)
742 758
 template.register_tag('regroup', do_regroup)
83  tests/othertests/templates.py
@@ -4,95 +4,120 @@
4 4
 class SomeClass:
5 5
     def __init__(self):
6 6
         self.otherclass = OtherClass()
7  
-        
  7
+
8 8
     def method(self):
9 9
         return "SomeClass.method"
10  
-        
  10
+
11 11
     def method2(self, o):
12 12
         return o
13 13
 
14 14
 class OtherClass:
15 15
     def method(self):
16 16
         return "OtherClass.method"
17  
-        
  17
+
18 18
 # SYNTAX --
19 19
 # 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
20 20
 TEMPLATE_TESTS = {
21 21
 
22 22
     ### BASIC SYNTAX ##########################################################
23  
-    
  23
+
24 24
     # Plain text should go through the template parser untouched
25 25
     'basic-syntax01': ("something cool", {}, "something cool"),
26  
-    
  26
+
27 27
     # Variables should be replaced with their value in the current context
28 28
     'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"),
29 29
 
30 30
     # More than one replacement variable is allowed in a template
31 31
     'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
32  
-    
  32
+
33 33
     # Fail silently when a variable is not found in the current context
34 34
     'basic-syntax04': ("as{{ missing }}df", {}, "asdf"),
35  
-    
  35
+
36 36
     # A variable may not contain more than one word
37 37
     'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
38  
-    
  38
+
39 39
     # Raise TemplateSyntaxError for empty variable tags
40 40
     'basic-syntax07': ("{{ }}",        {}, template.TemplateSyntaxError),
41 41
     'basic-syntax08': ("{{        }}", {}, template.TemplateSyntaxError),
42  
-    
  42
+
43 43
     # Attribute syntax allows a template to call an object's attribute
44 44
     'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"),
45  
-    
  45
+
46 46
     # Multiple levels of attribute access are allowed
47 47
     'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
48  
-    
  48
+
49 49
     # Fail silently when a variable's attribute isn't found
50 50
     'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""),
51  
-    
  51
+
52 52
     # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
53 53
     'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
54  
-    
  54
+
55 55
     # Raise TemplateSyntaxError when trying to access a variable containing an illegal character
56 56
     'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError),
57 57
     'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError),
58 58
     'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError),
59 59
     'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError),
60 60
     'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError),
61  
-    
  61
+
62 62
     # Attribute syntax allows a template to call a dictionary key's value
63 63
     'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
64  
-    
  64
+
65 65
     # Fail silently when a variable's dictionary key isn't found
66 66
     'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""),
67  
-    
  67
+
68 68
     # Fail silently when accessing a non-simple method
69 69
     'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""),
70  
-        
  70
+
71 71
     # Basic filter usage
72 72
     'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
73  
-    
  73
+
74 74
     # Chained filters
75 75
     'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"),
76  
-    
  76
+
77 77
     # Raise TemplateSyntaxError for space between a variable and filter pipe
78 78
     'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError),
79  
-    
  79
+
80 80
     # Raise TemplateSyntaxError for space after a filter pipe
81 81
     'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError),
82  
-    
  82
+
83 83
     # Raise TemplateSyntaxError for a nonexistent filter
84 84
     'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError),
85  
-    
  85
+
86 86
     # Raise TemplateSyntaxError when trying to access a filter containing an illegal character
87 87
     'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError),
88  
-    
  88
+
89 89
     # Raise TemplateSyntaxError for invalid block tags
90 90
     'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError),
91  
-    
  91
+
92 92
     # Raise TemplateSyntaxError for empty block tags
93 93
     'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError),
94  
-    
95  
-    ### INHERITANCE TESTS #####################################################
  94
+
  95
+    ### IF TAG ################################################################
  96
+    'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
  97
+    'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
  98
+    'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
  99
+
  100
+    ### COMMENT TAG ###########################################################
  101
+    'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
  102
+    'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
  103
+
  104
+    ### FOR TAG ###############################################################
  105
+    'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"),
  106
+    'for-tag02': ("{% for val in values reversed %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "321"),
  107
+
  108
+    ### IFEQUAL TAG ###########################################################
  109
+    'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
  110
+    'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"),
  111
+    'ifequal03': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 2}, "no"),
  112
+    'ifequal04': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 1}, "yes"),
  113
+
  114
+    ### IFNOTEQUAL TAG ########################################################
  115
+    'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
  116
+    'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
  117
+    'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
  118
+    'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"),
  119
+
  120
+    ### INHERITANCE ###########################################################
96 121
 
97 122
     # Standard template with no inheritance
98 123
     'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),
@@ -151,7 +176,7 @@ def method(self):
151 176
     # {% load %} tag (within a child template)
152 177
     'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'),
153 178
 
154  
-    ### EXCEPTION TESTS #######################################################
  179
+    ### EXCEPTIONS ############################################################
155 180
 
156 181
     # Raise exception for invalid template name
157 182
     'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
@@ -198,12 +223,12 @@ def run_tests(verbosity=0, standalone=False):
198 223
                 print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
199 224
             failed_tests.append(name)
200 225
     template_loader.load_template_source = old_template_loader
201  
-    
  226
+
202 227
     if failed_tests and not standalone:
203 228
         msg = "Template tests %s failed." % failed_tests
204 229
         if not verbosity:
205 230
             msg += "  Re-run tests with -v1 to see actual failures"
206 231
         raise Exception, msg
207  
-    
  232
+
208 233
 if __name__ == "__main__":
209 234
     run_tests(1, True)

0 notes on commit d80ac5a

Please sign in to comment.
Something went wrong with that request. Please try again.