mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		| @@ -806,8 +806,8 @@ def do_if(parser, token): | ||||
|     Arguments and operators _must_ have a space between them, so | ||||
|     ``{% if 1>2 %}`` is not a valid if tag. | ||||
|  | ||||
|     All supported operators are: ``or``, ``and``, ``in``, ``==`` (or ``=``), | ||||
|     ``!=``, ``>``, ``>=``, ``<`` and ``<=``. | ||||
|     All supported operators are: ``or``, ``and``, ``in``, ``not in`` | ||||
|     ``==`` (or ``=``), ``!=``, ``>``, ``>=``, ``<`` and ``<=``. | ||||
|  | ||||
|     Operator precedence follows Python. | ||||
|     """ | ||||
|   | ||||
| @@ -97,6 +97,7 @@ OPERATORS = { | ||||
|     'and': infix(7, lambda x, y: x and y), | ||||
|     'not': prefix(8, operator.not_), | ||||
|     '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.ne), | ||||
| @@ -150,11 +151,23 @@ class IfParser(object): | ||||
|     error_class = ValueError | ||||
|  | ||||
|     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.current_token = self.next() | ||||
|  | ||||
|     def translate_tokens(self, token): | ||||
|     def translate_token(self, token): | ||||
|         try: | ||||
|             op = OPERATORS[token] | ||||
|         except (KeyError, TypeError): | ||||
|   | ||||
| @@ -440,6 +440,11 @@ how ``x in y`` will be interpreted:: | ||||
|       instance that belongs to the QuerySet. | ||||
|     {% 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 | ||||
| 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 %}`` | ||||
| anymore, unless you're the nostalgic type. | ||||
|  | ||||
| The operators supported are ``==``, ``!=``, ``<``, ``>``, ``<=``, ``>=`` and | ||||
| ``in``, all of which work like the Python operators, in addition to ``and``, | ||||
| ``or`` and ``not``, which were already supported. | ||||
| The operators supported are ``==``, ``!=``, ``<``, ``>``, ``<=``, ``>=``, | ||||
| ``in`` and ``not in``, all of which work like the Python operators, in addition | ||||
|  to ``and``, ``or`` and ``not``, which were already supported. | ||||
|  | ||||
| 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, [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): | ||||
|         # (False and False) or True == True   <- we want this one, like Python | ||||
|         # 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-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 | ||||
|             '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'), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user