Commit c16b9dd8 authored by Alasdair Nicol's avatar Alasdair Nicol Committed by Tim Graham
Browse files

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

parent c10db4bd
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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')