Opened 11 years ago

Closed 11 years ago

#20966 closed Bug (duplicate)

Wrong table referenced in query with multiple joins

Reported by: stn Owned by: nobody
Component: Uncategorized Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

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

Change History (1)

comment:1 by stn, 11 years ago

Resolution: duplicate
Status: newclosed
Type: UncategorizedBug

Possible duplicate of #20788

Note: See TracTickets for help on using tickets.
Back to Top