Index: django/template/defaulttags.py
===================================================================
--- django/template/defaulttags.py	(revision 10604)
+++ django/template/defaulttags.py	(working copy)
@@ -232,22 +232,46 @@
         nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
         return nodes
 
+    def __in_list_helper(self, context, list_, val_):
+        from django.db.models.query import QuerySet
+        val_ = val_.resolve(context, True)
+        list_ = list_.resolve(context, True)
+        if isinstance(list_, QuerySet):
+            if hasattr(val_, 'pk'):
+                if list_._result_cache:
+                    in_list = val_ in list_
+                else:
+                    in_list = list_.filter(pk = val_.pk).count() > 0
+            else:
+                in_list = False
+        else:
+            in_list = val_ in list_
+        return in_list
+
     def render(self, context):
         if self.link_type == IfNode.LinkTypes.or_:
             for ifnot, bool_expr in self.bool_exprs:
-                try:
-                    value = bool_expr.resolve(context, True)
-                except VariableDoesNotExist:
-                    value = None
+                if isinstance(bool_expr, tuple):
+                    val_, list_ = bool_expr
+                    value = self.__in_list_helper(context, list_, val_)
+                else:
+                    try:
+                        value = bool_expr.resolve(context, True)
+                    except VariableDoesNotExist:
+                        value = None
                 if (value and not ifnot) or (ifnot and not value):
                     return self.nodelist_true.render(context)
             return self.nodelist_false.render(context)
         else:
             for ifnot, bool_expr in self.bool_exprs:
-                try:
-                    value = bool_expr.resolve(context, True)
-                except VariableDoesNotExist:
-                    value = None
+                if isinstance(bool_expr, tuple):
+                    val_, list_ = bool_expr
+                    value = self.__in_list_helper(context, list_, val_)
+                else:
+                    try:
+                        value = bool_expr.resolve(context, True)
+                    except VariableDoesNotExist:
+                        value = None
                 if not ((value and not ifnot) or (ifnot and not value)):
                     return self.nodelist_false.render(context)
             return self.nodelist_true.render(context)
@@ -778,6 +802,27 @@
             There are some athletes and absolutely no coaches.
         {% endif %}
 
+    ``if`` tags may also use ``in`` to test whether an object is (or is not) in a 
+    list::
+        
+        {% if user in athlete_list %}
+            User is an athlete
+        {% endif %}
+
+        {% if user not in coach_list %}
+            User is not a coach
+        {% endif %}
+
+        {% if user in athlete_list and not user in coach_list %}
+            User is an athlete, but not a coach
+        {% endif %}
+
+    When using the ``in`` operator to test whether an element is in a QuerySet,
+    the behaviour depends upon whether the queryset has been executed already.
+    If it has already been executed, the behaviour is to search the result set
+    manually. If it has not been executed, or no result set is available, it will
+    filter down the QuerySet to check for just this item. 
+
     ``if`` tags do not allow ``and`` and ``or`` clauses with the same tag,
     because the order of logic would be ambigous. For example, this is
     invalid::
@@ -810,13 +855,29 @@
             raise TemplateSyntaxError, "'if' tags can't mix 'and' and 'or'"
     for boolpair in boolpairs:
         if ' ' in boolpair:
-            try:
-                not_, boolvar = boolpair.split()
-            except ValueError:
-                raise TemplateSyntaxError, "'if' statement improperly formatted"
-            if not_ != 'not':
-                raise TemplateSyntaxError, "Expected 'not' in if statement"
-            boolvars.append((True, parser.compile_filter(boolvar)))
+            elems = boolpair.split()
+            num_elems = len(elems)
+            if num_elems == 2: # parse 'not val'
+                not_, boolvar = elems
+                if not_ != 'not':
+                    raise TemplateSyntaxError, "Expected 'not' in if statement"
+                boolvars.append((True, parser.compile_filter(boolvar)))
+            elif num_elems == 3: # parse 'val in list'
+                val_, in_, list_ = elems
+                if in_ != 'in':
+                    raise TemplateSyntaxError, "Expected 'in' in if statement"
+                boolvars.append((False, (parser.compile_filter(val_), parser.compile_filter(list_))))
+            elif num_elems == 4: # parse 'val not in list' and 'not val in list'
+                val_, not_, in_, list_ = elems
+                if val_ == 'not':
+                    val_, not_ = not_, val_
+                if not_ != 'not':
+                    raise TemplateSyntaxError, "Expected 'not' in if statement"
+                elif in_ != 'in':
+                    raise TemplateSyntaxError, "Expected 'in' in if statement"
+                boolvars.append((True, (parser.compile_filter(val_), parser.compile_filter(list_))))
+            else:
+                raise TemplateSyntaxError, "Invalid if statement"
         else:
             boolvars.append((False, parser.compile_filter(boolpair)))
     nodelist_true = parser.parse(('else', 'endif'))
Index: tests/regressiontests/templates/tests.py
===================================================================
--- tests/regressiontests/templates/tests.py	(revision 10604)
+++ tests/regressiontests/templates/tests.py	(working copy)
@@ -554,6 +554,22 @@
             'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
             'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
 
+            # IN
+            'if-tag-in01': ("{% if foo in list %}yes{% else %}no{% endif %}", {'foo': 'a', 'list': ['a', 'b', 'c']}, 'yes'),
+            'if-tag-in02': ("{% if foo in list %}yes{% else %}no{% endif %}", {'foo': 'x', 'list': ['a', 'b', 'c']}, 'no'),
+            'if-tag-in03': ("{% if not foo in list %}yes{% else %}no{% endif %}", {'foo': 'a', 'list': ['a', 'b', 'c']}, 'no'),
+            'if-tag-in04': ("{% if not foo in list %}yes{% else %}no{% endif %}", {'foo': 'x', 'list': ['a', 'b', 'c']}, 'yes'),
+            'if-tag-in05': ("{% if foo not in list %}yes{% else %}no{% endif %}", {'foo': 'a', 'list': ['a', 'b', 'c']}, 'no'),
+            'if-tag-in06': ("{% if foo not in list %}yes{% else %}no{% endif %}", {'foo': 'x', 'list': ['a', 'b', 'c']}, 'yes'),
+            'if-tag-in07': ("{% if foo and bar in list %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'a', 'list': ['a']}, 'yes'),
+            'if-tag-in08': ("{% if bar in list and foo %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'a', 'list': ['a']}, 'yes'),
+            'if-tag-in09': ("{% if foo and bar in list %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'b', 'list': ['a']}, 'no'),
+            'if-tag-in10': ("{% if bar in list and foo %}yes{% else %}no{% endif %}", {'foo': True, 'bar': 'b', 'list': ['a']}, 'no'),
+            'if-tag-in11': ("{% if foo or bar in list %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'a', 'list': ['a']}, 'yes'),
+            'if-tag-in12': ("{% if bar in list or foo %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'a', 'list': ['a']}, 'yes'),
+            'if-tag-in13': ("{% if foo or bar in list %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'b', 'list': ['a']}, 'no'),
+            'if-tag-in14': ("{% if bar in list or foo %}yes{% else %}no{% endif %}", {'foo': False, 'bar': 'b', 'list': ['a']}, 'no'),
+
             # TODO: multiple ORs
 
             # NOT
