﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
20966	Wrong table referenced in query with multiple joins	stn	nobody	"With following example (using prehistoric Django v.1.4):

{{{
from django.db import models

class AQuerySet(models.query.QuerySet):
    def filter_(self):
        return self.exclude(b__c__c2__x=1)

    def exclude_(self):
        return self.exclude(b__c__c2__x=1)

class AManager(models.Manager):
    def get_query_set(self):
        return AQuerySet(self.model)

    def filter_(self):
        return self.get_query_set().filter_()

    def exclude_(self):
        return self.get_query_set().exclude_()

# Create your models here.
class A(models.Model):
    b = models.ForeignKey('example.B', null=True, blank=True, default=None)
    objects = AManager()

    @classmethod
    def setup_test(cls):
        A.teardown()
        c2 = C2.objects.create()
        b = B.objects.create(c=c2)
        b = B.objects.create(c=c2)
        B.objects.get(pk=1).delete()
        a = A.objects.create(b=b)

    @classmethod
    def teardown(cls):
        C2.objects.all().delete()
        C1.objects.all().delete()
        B.objects.all().delete()
        A.objects.all().delete()

class B(models.Model):
    c = models.ForeignKey('example.C1', null=True, blank=True, default=None)

class C1(models.Model):
    pass

class C2(C1):
    x = models.IntegerField(default=1)


}}}

Code below returns same results for filter_, as well as exclude_ call. It seems that this part of SQL query:
WHERE NOT ((""example_b"".""c_id"" IN (SELECT U1.""id"" FROM ""example_b"" U1))
selects c_id column from example_b table and compares it with id of B object. It has happened to me when using PostgreSQL, but this example was reproduced using SQLite3.  

{{{

>>> A.setup_test()
>>> [a.pk for a in A.objects.all()]
[1]
>>> [b.pk for b in B.objects.all()]
[2]
>>> [c.pk for c in C1.objects.all()]
[1]
>>> [c.pk for c in C2.objects.all()]
[1]
>>> A.objects.filter_()
[<A: A object>]
>>> A.objects.filter_().query
<django.db.models.sql.query.Query object at 0x3b50250>
>>> print A.objects.filter_().query
SELECT ""example_a"".""id"", ""example_a"".""b_id"" FROM ""example_a"" INNER JOIN ""example_b"" ON (""example_a"".""b_id"" = ""example_b"".""id"") INNER JOIN ""example_c1""
 ON (""example_b"".""c_id"" = ""example_c1"".""id"") INNER JOIN ""example_c2"" ON (""example_c1"".""id"" = ""example_c2"".""c1_ptr_id"") WHERE ""example_c2"".""x"" = 1 
>>> A.objects.exclude_()
[<A: A object>]
>>> print A.objects.exclude_().query
SELECT ""example_a"".""id"", ""example_a"".""b_id"" FROM ""example_a"" LEFT OUTER JOIN ""example_b"" ON (""example_a"".""b_id"" = ""example_b"".""id"") LEFT OUTER JOIN ""e
xample_c1"" ON (""example_b"".""c_id"" = ""example_c1"".""id"") WHERE NOT ((""example_b"".""c_id"" IN (SELECT U1.""id"" FROM ""example_b"" U1 INNER JOIN ""example_c1"" U
2 ON (U1.""c_id"" = U2.""id"") INNER JOIN ""example_c2"" U3 ON (U2.""id"" = U3.""c1_ptr_id"") WHERE (U3.""x"" = 1  AND U1.""id"" IS NOT NULL)) AND NOT (""example_b"".
""id"" IS NULL) AND ""example_c1"".""id"" IS NOT NULL))
>>> A.objects.exclude_().get().b.c.c2.x
1

}}}

As you can see, even though we have excluded objects with 
{{{
self.exclude(b__c__c2__x=1)
}}}

we receive 
{{{
A.objects.exclude_().get().b.c.c2.x == 1
}}}
"	Bug	closed	Uncategorized	1.4	Normal	duplicate			Unreviewed	0	0	0	0	0	0
