Opened 12 years ago
Closed 12 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 , 12 years ago
| Resolution: | → duplicate |
|---|---|
| Status: | new → closed |
| Type: | Uncategorized → Bug |
Note:
See TracTickets
for help on using tickets.
Possible duplicate of #20788