Index: AUTHORS
===================================================================
--- AUTHORS	(revision 16649)
+++ AUTHORS	(working copy)
@@ -448,6 +448,7 @@
     schwank@gmail.com
     scott@staplefish.com
     Ilya Semenov <semenov@inetss.com>
+    Aleksandra Sendecka <asendecka@hauru.eu>
     serbaut@gmail.com
     John Shaffer <jshaffer2112@gmail.com>
     Pete Shinners <pete@shinners.org>
Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py	(revision 16649)
+++ django/db/models/sql/query.py	(working copy)
@@ -1098,7 +1098,8 @@
 
         # Process the join list to see if we can remove any inner joins from
         # the far end (fewer tables in a query is better).
-        col, alias, join_list = self.trim_joins(target, join_list, last, trim)
+        isnull_skip = lookup_type == 'isnull' and value is False
+        col, alias, join_list = self.trim_joins(target, join_list, last, trim, isnull_skip)
         if connector == OR:
             # Some joins may need to be promoted when adding a new filter to a
             # disjunction. We walk the list of new joins and where it diverges
@@ -1435,7 +1436,7 @@
 
         return field, target, opts, joins, last, extra_filters
 
-    def trim_joins(self, target, join_list, last, trim):
+    def trim_joins(self, target, join_list, last, trim, isnull_skip = False):
         """
         Sometimes joins at the end of a multi-table sequence can be trimmed. If
         the final join is against the same column as we are comparing against,
@@ -1476,7 +1477,7 @@
         alias = join_list[-1]
         while final > 1:
             join = self.alias_map[alias]
-            if col != join[RHS_JOIN_COL] or join[JOIN_TYPE] != self.INNER:
+            if col != join[RHS_JOIN_COL] or join[JOIN_TYPE] != self.INNER or isnull_skip:
                 break
             self.unref_alias(alias)
             alias = join[LHS_ALIAS]
Index: tests/regressiontests/queries/tests.py
===================================================================
--- tests/regressiontests/queries/tests.py	(revision 16649)
+++ tests/regressiontests/queries/tests.py	(working copy)
@@ -15,7 +15,7 @@
     DumbCategory, ExtraInfo, Fan, Item, LeafA, LoopX, LoopZ, ManagedModel,
     Member, NamedCategory, Note, Number, Plaything, PointerA, Ranking, Related,
     Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten, Node, ObjectA, ObjectB,
-    ObjectC)
+    ObjectC, CategoryItem, SimpleCategory, SpecialCategory, OneToOneCategory)
 
 
 class BaseQuerysetTest(TestCase):
@@ -1043,7 +1043,231 @@
             []
         )
 
+    def test_ticket15316_filter_false(self):
+        c1 = SimpleCategory(name="category1")
+        c2 = SpecialCategory(name="named category1", special_name="special1")
+        c3 = SpecialCategory(name="named category2", special_name="special2")
+        c1.save()
+        c2.save()
+        c3.save()
 
+        ci1 = CategoryItem(category=c1)
+        ci2 = CategoryItem(category=c2)
+        ci3 = CategoryItem(category=c3)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+        CategoryItem.objects.filter(category__specialcategory__isnull=False).count(),
+            2
+        )
+        self.assertItemsEqual(
+            CategoryItem.objects.filter(category__specialcategory__isnull=False),
+            CategoryItem.objects.filter(pk__in=[ci2.pk, ci3.pk])
+        )
+
+    def test_ticket15316_exclude_false(self):
+        c1 = SimpleCategory(name="category1")
+        c2 = SpecialCategory(name="named category1", special_name="special1")
+        c3 = SpecialCategory(name="named category2", special_name="special2")
+        c1.save()
+        c2.save()
+        c3.save()
+
+        ci1 = CategoryItem(category=c1)
+        ci2 = CategoryItem(category=c2)
+        ci3 = CategoryItem(category=c3)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+            CategoryItem.objects.exclude(category__specialcategory__isnull=False).count(),
+            1
+        )
+        self.assertItemsEqual(
+            CategoryItem.objects.exclude(category__specialcategory__isnull=False),
+            CategoryItem.objects.filter(pk__in=[ci1.pk])
+        )
+
+    def test_ticket15316_filter_true(self):
+        c1 = SimpleCategory(name="category1")
+        c2 = SpecialCategory(name="named category1", special_name="special1")
+        c3 = SpecialCategory(name="named category2", special_name="special2")
+        c1.save()
+        c2.save()
+        c3.save()
+        ci1 = CategoryItem(category=c1)
+        ci2 = CategoryItem(category=c2)
+        ci3 = CategoryItem(category=c3)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+            CategoryItem.objects.filter(category__specialcategory__isnull=True).count(),
+            1
+        )
+
+        self.assertItemsEqual(
+            CategoryItem.objects.filter(category__specialcategory__isnull=True),
+            CategoryItem.objects.filter(pk__in=[ci1.pk])
+        )
+
+    def test_ticket15316_exclude_true(self):
+        c1 = SimpleCategory(name="category1")
+        c2 = SpecialCategory(name="named category1", special_name="special1")
+        c3 = SpecialCategory(name="named category2", special_name="special2")
+        c1.save()
+        c2.save()
+        c3.save()
+
+        ci1 = CategoryItem(category=c1)
+        ci2 = CategoryItem(category=c2)
+        ci3 = CategoryItem(category=c3)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+            CategoryItem.objects.exclude(category__specialcategory__isnull=True).count(),
+            2
+        )
+
+        self.assertItemsEqual(
+            CategoryItem.objects.exclude(category__specialcategory__isnull=True),
+            CategoryItem.objects.filter(pk__in=[ci2.pk, ci3.pk])
+        )
+
+    def test_ticket15316_one2one_filter_false(self):
+        c  = SimpleCategory(name="cat")
+        c0 = SimpleCategory(name="cat0")
+        c1 = SimpleCategory(name="category1")
+
+        c.save()
+        c0.save()
+        c1.save()
+        
+        c2 = OneToOneCategory(category = c1, new_name="new1")
+        c3 = OneToOneCategory(category = c0, new_name="new2")
+
+        c2.save()
+        c3.save()
+
+        ci1 = CategoryItem(category=c)
+        ci2 = CategoryItem(category=c0)
+        ci3 = CategoryItem(category=c1)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+        CategoryItem.objects.filter(category__onetoonecategory__isnull=False).count(),
+            2
+        )
+        self.assertItemsEqual(
+            CategoryItem.objects.filter(category__onetoonecategory__isnull=False),
+            CategoryItem.objects.filter(pk__in=[ci2.pk, ci3.pk])
+        )
+
+    def test_ticket15316_one2one_exclude_false(self):
+        c  = SimpleCategory(name="cat")
+        c0 = SimpleCategory(name="cat0")
+        c1 = SimpleCategory(name="category1")
+
+        c.save()
+        c0.save()
+        c1.save()
+
+        c2 = OneToOneCategory(category = c1, new_name="new1")
+        c3 = OneToOneCategory(category = c0, new_name="new2")
+
+        c2.save()
+        c3.save()
+
+        ci1 = CategoryItem(category=c)
+        ci2 = CategoryItem(category=c0)
+        ci3 = CategoryItem(category=c1)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+            CategoryItem.objects.exclude(category__onetoonecategory__isnull=False).count(),
+            1
+        )
+        self.assertItemsEqual(
+            CategoryItem.objects.exclude(category__onetoonecategory__isnull=False),
+            CategoryItem.objects.filter(pk__in=[ci1.pk])
+        )
+
+    def test_ticket15316_one2one_filter_true(self):
+        c  = SimpleCategory(name="cat")
+        c0 = SimpleCategory(name="cat0")
+        c1 = SimpleCategory(name="category1")
+
+        c.save()
+        c0.save()
+        c1.save()
+
+        c2 = OneToOneCategory(category = c1, new_name="new1")
+        c3 = OneToOneCategory(category = c0, new_name="new2")
+
+        c2.save()
+        c3.save()
+
+        ci1 = CategoryItem(category=c)
+        ci2 = CategoryItem(category=c0)
+        ci3 = CategoryItem(category=c1)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+            CategoryItem.objects.filter(category__onetoonecategory__isnull=True).count(),
+            1
+        )
+
+        self.assertItemsEqual(
+            CategoryItem.objects.filter(category__onetoonecategory__isnull=True),
+            CategoryItem.objects.filter(pk__in=[ci1.pk])
+        )
+
+    def test_ticket15316_one2one_exclude_true(self):
+        c  = SimpleCategory(name="cat")
+        c0 = SimpleCategory(name="cat0")
+        c1 = SimpleCategory(name="category1")
+
+        c.save()
+        c0.save()
+        c1.save()
+
+        c2 = OneToOneCategory(category = c1, new_name="new1")
+        c3 = OneToOneCategory(category = c0, new_name="new2")
+
+        c2.save()
+        c3.save()
+
+        ci1 = CategoryItem(category=c)
+        ci2 = CategoryItem(category=c0)
+        ci3 = CategoryItem(category=c1)
+        ci1.save()
+        ci2.save()
+        ci3.save()
+
+        self.assertEqual(
+            CategoryItem.objects.exclude(category__onetoonecategory__isnull=True).count(),
+            2
+        )
+
+        self.assertItemsEqual(
+            CategoryItem.objects.exclude(category__onetoonecategory__isnull=True),
+            CategoryItem.objects.filter(pk__in=[ci2.pk, ci3.pk])
+        )
+
+
+
 class Queries5Tests(TestCase):
     def setUp(self):
         # Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering
Index: tests/regressiontests/queries/models.py
===================================================================
--- tests/regressiontests/queries/models.py	(revision 16649)
+++ tests/regressiontests/queries/models.py	(working copy)
@@ -317,3 +317,29 @@
 
     def __unicode__(self):
        return self.name
+
+class SimpleCategory(models.Model):
+    name = models.CharField(max_length=10)
+
+    def __unicode__(self):
+        return self.name
+
+class SpecialCategory(SimpleCategory):
+    special_name = models.CharField(max_length=10)
+
+    def __unicode__(self):
+        return self.name + " " + self.special_name
+
+class CategoryItem(models.Model):
+    category = models.ForeignKey(SimpleCategory)
+
+    def __unicode__(self):
+ 	    return "category item: " + str(self.category)
+
+class OneToOneCategory(models.Model):
+    new_name = models.CharField(max_length=10)
+    category = models.OneToOneField(SimpleCategory)
+
+    def __unicode__(self):
+        return "one2one " + self.new_name
+    
\ No newline at end of file
