فهرست منبع

Fixed #26479 -- Added 'is not' operator to the if tag.

Alasdair Nicol 9 سال پیش
والد
کامیت
c16b9dd8e0
4فایلهای تغییر یافته به همراه33 افزوده شده و 4 حذف شده
  1. 6 2
      django/template/smartif.py
  2. 14 1
      docs/ref/templates/builtins.txt
  3. 1 1
      docs/releases/1.10.txt
  4. 12 0
      tests/template_tests/syntax_tests/test_if.py

+ 6 - 2
django/template/smartif.py

@@ -97,6 +97,7 @@ OPERATORS = {
     'in': infix(9, lambda context, x, y: x.eval(context) in y.eval(context)),
     'not in': infix(9, lambda context, x, y: x.eval(context) not in y.eval(context)),
     'is': infix(10, lambda context, x, y: x.eval(context) is y.eval(context)),
+    'is not': infix(10, lambda context, x, y: x.eval(context) is not y.eval(context)),
     '==': infix(10, lambda context, x, y: x.eval(context) == y.eval(context)),
     '!=': infix(10, lambda context, x, y: x.eval(context) != y.eval(context)),
     '>': infix(10, lambda context, x, y: x.eval(context) > y.eval(context)),
@@ -149,13 +150,16 @@ class IfParser(object):
     error_class = ValueError
 
     def __init__(self, tokens):
-        # pre-pass necessary to turn  'not','in' into single token
+        # Turn 'is','not' and 'not','in' into single tokens.
         l = len(tokens)
         mapped_tokens = []
         i = 0
         while i < l:
             token = tokens[i]
-            if token == "not" and i + 1 < l and tokens[i + 1] == "in":
+            if token == "is" and i + 1 < l and tokens[i + 1] == "not":
+                token = "is not"
+                i += 1  # skip 'not'
+            elif token == "not" and i + 1 < l and tokens[i + 1] == "in":
                 token = "not in"
                 i += 1  # skip 'in'
             mapped_tokens.append(self.translate_token(token))

+ 14 - 1
docs/ref/templates/builtins.txt

@@ -432,7 +432,8 @@ Use of actual parentheses in the :ttag:`if` tag is invalid syntax. If you need
 them to indicate precedence, you should use nested :ttag:`if` tags.
 
 :ttag:`if` tags may also use the operators ``==``, ``!=``, ``<``, ``>``,
-``<=``, ``>=``, ``in``, and ``is`` which work as follows:
+``<=``, ``>=``, ``in``, ``not in``, ``is``, and ``is not`` which work as
+follows:
 
 ``==`` operator
 ^^^^^^^^^^^^^^^
@@ -526,6 +527,18 @@ Object identity. Tests if two values are the same object. Example::
       This will output if and only if value is None.
     {% endif %}
 
+``is not`` operator
+^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 1.10
+
+Tests if two values are not the same object. This is the negation of
+the ``is`` operator. Example::
+
+    {% if value is not None %}
+      This will output if and only if value is not None.
+    {% endif %}
+
 Filters
 ~~~~~~~
 

+ 1 - 1
docs/releases/1.10.txt

@@ -409,7 +409,7 @@ Templates
   :class:`~django.template.backends.django.DjangoTemplates` backend and the
   :class:`~django.template.Engine` class.
 
-* Added the ``is`` comparison operator to the :ttag:`if` tag.
+* Added the ``is`` and ``is not`` comparison operators to the :ttag:`if` tag.
 
 * Allowed :tfilter:`dictsort` to order a list of lists by an element at a
   specified index.

+ 12 - 0
tests/template_tests/syntax_tests/test_if.py

@@ -537,3 +537,15 @@ class IfTagTests(SimpleTestCase):
     def test_if_is_no_match(self):
         output = self.engine.render_to_string('template', {'foo': 1})
         self.assertEqual(output, 'no')
+
+    @setup({'template': '{% if foo is not None %}yes{% else %}no{% endif %}'})
+    def test_if_is_not_match(self):
+        # For this to act as a regression test, it's important not to use
+        # foo=True because True is (not None)
+        output = self.engine.render_to_string('template', {'foo': False})
+        self.assertEqual(output, 'yes')
+
+    @setup({'template': '{% if foo is not None %}yes{% else %}no{% endif %}'})
+    def test_if_is_not_no_match(self):
+        output = self.engine.render_to_string('template', {'foo': None})
+        self.assertEqual(output, 'no')