Fixed #13058 - "smart if" template tag doesn't support "if not in ..." condition
Thanks to ramusus for the report. git-svn-id: http://code.djangoproject.com/svn/django/trunk@12732 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
021ba30ad1
commit
960af90279
|
@ -806,8 +806,8 @@ def do_if(parser, token):
|
||||||
Arguments and operators _must_ have a space between them, so
|
Arguments and operators _must_ have a space between them, so
|
||||||
``{% if 1>2 %}`` is not a valid if tag.
|
``{% if 1>2 %}`` is not a valid if tag.
|
||||||
|
|
||||||
All supported operators are: ``or``, ``and``, ``in``, ``==`` (or ``=``),
|
All supported operators are: ``or``, ``and``, ``in``, ``not in``
|
||||||
``!=``, ``>``, ``>=``, ``<`` and ``<=``.
|
``==`` (or ``=``), ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
|
||||||
|
|
||||||
Operator precedence follows Python.
|
Operator precedence follows Python.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -97,6 +97,7 @@ OPERATORS = {
|
||||||
'and': infix(7, lambda x, y: x and y),
|
'and': infix(7, lambda x, y: x and y),
|
||||||
'not': prefix(8, operator.not_),
|
'not': prefix(8, operator.not_),
|
||||||
'in': infix(9, lambda x, y: x in y),
|
'in': infix(9, lambda x, y: x in y),
|
||||||
|
'not in': infix(9, lambda x, y: x not in y),
|
||||||
'=': infix(10, operator.eq),
|
'=': infix(10, operator.eq),
|
||||||
'==': infix(10, operator.eq),
|
'==': infix(10, operator.eq),
|
||||||
'!=': infix(10, operator.ne),
|
'!=': infix(10, operator.ne),
|
||||||
|
@ -150,11 +151,23 @@ class IfParser(object):
|
||||||
error_class = ValueError
|
error_class = ValueError
|
||||||
|
|
||||||
def __init__(self, tokens):
|
def __init__(self, tokens):
|
||||||
self.tokens = map(self.translate_tokens, tokens)
|
# pre-pass necessary to turn 'not','in' into single token
|
||||||
|
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":
|
||||||
|
token = "not in"
|
||||||
|
i += 1 # skip 'in'
|
||||||
|
mapped_tokens.append(self.translate_token(token))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
self.tokens = mapped_tokens
|
||||||
self.pos = 0
|
self.pos = 0
|
||||||
self.current_token = self.next()
|
self.current_token = self.next()
|
||||||
|
|
||||||
def translate_tokens(self, token):
|
def translate_token(self, token):
|
||||||
try:
|
try:
|
||||||
op = OPERATORS[token]
|
op = OPERATORS[token]
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
|
|
|
@ -440,6 +440,11 @@ how ``x in y`` will be interpreted::
|
||||||
instance that belongs to the QuerySet.
|
instance that belongs to the QuerySet.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
``not in`` operator
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Not contained within. This is the negation of the ``in`` operator.
|
||||||
|
|
||||||
|
|
||||||
The comparison operators cannot be 'chained' like in Python or in mathematical
|
The comparison operators cannot be 'chained' like in Python or in mathematical
|
||||||
notation. For example, instead of using::
|
notation. For example, instead of using::
|
||||||
|
|
|
@ -636,9 +636,9 @@ You can now do this:
|
||||||
There's really no reason to use ``{% ifequal %}`` or ``{% ifnotequal %}``
|
There's really no reason to use ``{% ifequal %}`` or ``{% ifnotequal %}``
|
||||||
anymore, unless you're the nostalgic type.
|
anymore, unless you're the nostalgic type.
|
||||||
|
|
||||||
The operators supported are ``==``, ``!=``, ``<``, ``>``, ``<=``, ``>=`` and
|
The operators supported are ``==``, ``!=``, ``<``, ``>``, ``<=``, ``>=``,
|
||||||
``in``, all of which work like the Python operators, in addition to ``and``,
|
``in`` and ``not in``, all of which work like the Python operators, in addition
|
||||||
``or`` and ``not``, which were already supported.
|
to ``and``, ``or`` and ``not``, which were already supported.
|
||||||
|
|
||||||
Also, filters may now be used in the ``if`` expression. For example:
|
Also, filters may now be used in the ``if`` expression. For example:
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,13 @@ class SmartIfTests(unittest.TestCase):
|
||||||
self.assertCalcEqual(False, [1, 'in', None])
|
self.assertCalcEqual(False, [1, 'in', None])
|
||||||
self.assertCalcEqual(False, [None, 'in', list_])
|
self.assertCalcEqual(False, [None, 'in', list_])
|
||||||
|
|
||||||
|
def test_not_in(self):
|
||||||
|
list_ = [1,2,3]
|
||||||
|
self.assertCalcEqual(False, [1, 'not', 'in', list_])
|
||||||
|
self.assertCalcEqual(True, [4, 'not', 'in', list_])
|
||||||
|
self.assertCalcEqual(False, [1, 'not', 'in', None])
|
||||||
|
self.assertCalcEqual(True, [None, 'not', 'in', list_])
|
||||||
|
|
||||||
def test_precedence(self):
|
def test_precedence(self):
|
||||||
# (False and False) or True == True <- we want this one, like Python
|
# (False and False) or True == True <- we want this one, like Python
|
||||||
# False and (False or True) == False
|
# False and (False or True) == False
|
||||||
|
|
|
@ -611,6 +611,12 @@ class Templates(unittest.TestCase):
|
||||||
'if-tag-lte-01': ("{% if 1 <= 1 %}yes{% else %}no{% endif %}", {}, "yes"),
|
'if-tag-lte-01': ("{% if 1 <= 1 %}yes{% else %}no{% endif %}", {}, "yes"),
|
||||||
'if-tag-lte-02': ("{% if 2 <= 1 %}yes{% else %}no{% endif %}", {}, "no"),
|
'if-tag-lte-02': ("{% if 2 <= 1 %}yes{% else %}no{% endif %}", {}, "no"),
|
||||||
|
|
||||||
|
# Contains
|
||||||
|
'if-tag-in-01': ("{% if 1 in x %}yes{% else %}no{% endif %}", {'x':[1]}, "yes"),
|
||||||
|
'if-tag-in-02': ("{% if 2 in x %}yes{% else %}no{% endif %}", {'x':[1]}, "no"),
|
||||||
|
'if-tag-not-in-01': ("{% if 1 not in x %}yes{% else %}no{% endif %}", {'x':[1]}, "no"),
|
||||||
|
'if-tag-not-in-02': ("{% if 2 not in x %}yes{% else %}no{% endif %}", {'x':[1]}, "yes"),
|
||||||
|
|
||||||
# AND
|
# AND
|
||||||
'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
|
'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
|
||||||
'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
|
'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
|
||||||
|
|
Loading…
Reference in New Issue