summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlasdair Nicol <alasdair@thenicols.net>2016-04-09 16:25:00 +0100
committerTim Graham <timograham@gmail.com>2016-04-09 13:01:15 -0400
commitc16b9dd8e0ae757616e9accbaffecc521191ee98 (patch)
tree691989f2102021cbbbad9fb27b3a28e10fc602e3
parentc10db4bd1b069739687b99d6b32b946634237431 (diff)
Fixed #26479 -- Added 'is not' operator to the if tag.
-rw-r--r--django/template/smartif.py8
-rw-r--r--docs/ref/templates/builtins.txt15
-rw-r--r--docs/releases/1.10.txt2
-rw-r--r--tests/template_tests/syntax_tests/test_if.py12
4 files changed, 33 insertions, 4 deletions
diff --git a/django/template/smartif.py b/django/template/smartif.py
index 718c457c60..b5ae510b0f 100644
--- a/django/template/smartif.py
+++ b/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))
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index 37abc62608..e11646f6bb 100644
--- a/docs/ref/templates/builtins.txt
+++ b/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
~~~~~~~
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index adae2524da..2002905b2d 100644
--- a/docs/releases/1.10.txt
+++ b/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.
diff --git a/tests/template_tests/syntax_tests/test_if.py b/tests/template_tests/syntax_tests/test_if.py
index 507a26b0b7..c4b5c53250 100644
--- a/tests/template_tests/syntax_tests/test_if.py
+++ b/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')