Ticket #8087: django-if-in-list.diff

File django-if-in-list.diff, 7.8 KB (added by tomevans222, 6 years ago)
  • django/template/defaulttags.py

     
    232232        nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
    233233        return nodes
    234234
     235    def __in_list_helper(self, context, list_, val_):
     236        from django.db.models.query import QuerySet
     237        val_ = val_.resolve(context, True)
     238        list_ = list_.resolve(context, True)
     239        if isinstance(list_, QuerySet):
     240            if hasattr(val_, 'pk'):
     241                if list_._result_cache:
     242                    in_list = val_ in list_
     243                else:
     244                    in_list = list_.filter(pk = val_.pk).count() > 0
     245            else:
     246                in_list = False
     247        else:
     248            in_list = val_ in list_
     249        return in_list
     250
    235251    def render(self, context):
    236252        if self.link_type == IfNode.LinkTypes.or_:
    237253            for ifnot, bool_expr in self.bool_exprs:
    238                 try:
    239                     value = bool_expr.resolve(context, True)
    240                 except VariableDoesNotExist:
    241                     value = None
     254                if isinstance(bool_expr, tuple):
     255                    val_, list_ = bool_expr
     256                    value = self.__in_list_helper(context, list_, val_)
     257                else:
     258                    try:
     259                        value = bool_expr.resolve(context, True)
     260                    except VariableDoesNotExist:
     261                        value = None
    242262                if (value and not ifnot) or (ifnot and not value):
    243263                    return self.nodelist_true.render(context)
    244264            return self.nodelist_false.render(context)
    245265        else:
    246266            for ifnot, bool_expr in self.bool_exprs:
    247                 try:
    248                     value = bool_expr.resolve(context, True)
    249                 except VariableDoesNotExist:
    250                     value = None
     267                if isinstance(bool_expr, tuple):
     268                    val_, list_ = bool_expr
     269                    value = self.__in_list_helper(context, list_, val_)
     270                else:
     271                    try:
     272                        value = bool_expr.resolve(context, True)
     273                    except VariableDoesNotExist:
     274                        value = None
    251275                if not ((value and not ifnot) or (ifnot and not value)):
    252276                    return self.nodelist_false.render(context)
    253277            return self.nodelist_true.render(context)
     
    778802            There are some athletes and absolutely no coaches.
    779803        {% endif %}
    780804
     805    ``if`` tags may also use ``in`` to test whether an object is (or is not) in a
     806    list::
     807       
     808        {% if user in athlete_list %}
     809            User is an athlete
     810        {% endif %}
     811
     812        {% if user not in coach_list %}
     813            User is not a coach
     814        {% endif %}
     815
     816        {% if user in athlete_list and not user in coach_list %}
     817            User is an athlete, but not a coach
     818        {% endif %}
     819
     820    When using the ``in`` operator to test whether an element is in a QuerySet,
     821    the behaviour depends upon whether the queryset has been executed already.
     822    If it has already been executed, the behaviour is to search the result set
     823    manually. If it has not been executed, or no result set is available, it will
     824    filter down the QuerySet to check for just this item.
     825
    781826    ``if`` tags do not allow ``and`` and ``or`` clauses with the same tag,
    782827    because the order of logic would be ambigous. For example, this is
    783828    invalid::
     
    810855            raise TemplateSyntaxError, "'if' tags can't mix 'and' and 'or'"
    811856    for boolpair in boolpairs:
    812857        if ' ' in boolpair:
    813             try:
    814                 not_, boolvar = boolpair.split()
    815             except ValueError:
    816                 raise TemplateSyntaxError, "'if' statement improperly formatted"
    817             if not_ != 'not':
    818                 raise TemplateSyntaxError, "Expected 'not' in if statement"
    819             boolvars.append((True, parser.compile_filter(boolvar)))
     858            elems = boolpair.split()
     859            num_elems = len(elems)
     860            if num_elems == 2: # parse 'not val'
     861                not_, boolvar = elems
     862                if not_ != 'not':
     863                    raise TemplateSyntaxError, "Expected 'not' in if statement"
     864                boolvars.append((True, parser.compile_filter(boolvar)))
     865            elif num_elems == 3: # parse 'val in list'
     866                val_, in_, list_ = elems
     867                if in_ != 'in':
     868                    raise TemplateSyntaxError, "Expected 'in' in if statement"
     869                boolvars.append((False, (parser.compile_filter(val_), parser.compile_filter(list_))))
     870            elif num_elems == 4: # parse 'val not in list' and 'not val in list'
     871                val_, not_, in_, list_ = elems
     872                if val_ == 'not':
     873                    val_, not_ = not_, val_
     874                if not_ != 'not':
     875                    raise TemplateSyntaxError, "Expected 'not' in if statement"
     876                elif in_ != 'in':
     877                    raise TemplateSyntaxError, "Expected 'in' in if statement"
     878                boolvars.append((True, (parser.compile_filter(val_), parser.compile_filter(list_))))
     879            else:
     880                raise TemplateSyntaxError, "Invalid if statement"
    820881        else:
    821882            boolvars.append((False, parser.compile_filter(boolpair)))
    822883    nodelist_true = parser.parse(('else', 'endif'))
  • tests/regressiontests/templates/tests.py

     
    554554            'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
    555555            'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
    556556
     557            # IN
     558            'if-tag-in01': ("{% if foo in list %}yes{% else %}no{% endif %}", {'foo': 'a', 'list': ['a', 'b', 'c']}, 'yes'),
     559            'if-tag-in02': ("{% if foo in list %}yes{% else %}no{% endif %}", {'foo': 'x', 'list': ['a', 'b', 'c']}, 'no'),
     560            'if-tag-in03': ("{% if not foo in list %}yes{% else %}no{% endif %}", {'foo': 'a', 'list': ['a', 'b', 'c']}, 'no'),
     561            'if-tag-in04': ("{% if not foo in list %}yes{% else %}no{% endif %}", {'foo': 'x', 'list': ['a', 'b', 'c']}, 'yes'),
     562            'if-tag-in05': ("{% if foo not in list %}yes{% else %}no{% endif %}", {'foo': 'a', 'list': ['a', 'b', 'c']}, 'no'),
     563            'if-tag-in06': ("{% if foo not in list %}yes{% else %}no{% endif %}", {'foo': 'x', 'list': ['a', 'b', 'c']}, 'yes'),
     564            'if-tag-in07': ("{% if foo and bar in list %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'a', 'list': ['a']}, 'yes'),
     565            'if-tag-in08': ("{% if bar in list and foo %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'a', 'list': ['a']}, 'yes'),
     566            'if-tag-in09': ("{% if foo and bar in list %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'b', 'list': ['a']}, 'no'),
     567            'if-tag-in10': ("{% if bar in list and foo %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'b', 'list': ['a']}, 'no'),
     568            'if-tag-in11': ("{% if foo or bar in list %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'a', 'list': ['a']}, 'yes'),
     569            'if-tag-in12': ("{% if bar in list or foo %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'a', 'list': ['a']}, 'yes'),
     570            'if-tag-in13': ("{% if foo or bar in list %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'b', 'list': ['a']}, 'no'),
     571            'if-tag-in14': ("{% if bar in list or foo %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'b', 'list': ['a']}, 'no'),
     572
    557573            # TODO: multiple ORs
    558574
    559575            # NOT
Back to Top