Opened 17 years ago
Closed 17 years ago
#6981 closed (fixed)
Nullable foreign keys use inner joins with select related
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | queryset-refactor |
Severity: | Keywords: | qs-rf | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Short version - if select related has name of nullable foreign key as an argument, inner joins are used and all objects with null are filtered.
I don't know if it is a problem - maybe it should be so. But it is not intuitive.
Long version (example):
from django.db import models class One(models.Model): a = models.IntegerField() class Two(models.Model): b = models.IntegerField() class Three(models.Model): c = models.IntegerField() one = models.ForeignKey(One) two = models.ForeignKey(Two, null=True)
>>> from tmp.models import One, Two, Three >>> from django.db import connection >>> >>> One.objects.all().delete() >>> first = [One.objects.create(a=a) for a in range(10)] >>> >>> Two.objects.all().delete() >>> second = [Two.objects.create(b=b) for b in range(10)] >>> >>> Three.objects.all().delete() >>> for c in range(10): ... one = first[c] ... two = c % 2 and second[c] or None ... Three.objects.create(c=c, one=one, two=two) >>> >>> # No select related ... print len(Three.objects.all()) 10 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id" FROM "tmp_three" >>> >>> # Select related without argument - only not-null foreign keys are used >>> print len(Three.objects.select_related()) 10 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id", "tmp_one"."id", "tmp_one"."a" FROM "tmp_three" INNER JOIN "tmp_one" ON ("tmp_three"."one_id" = "tmp_one"."id") >>> >>> # Select related with argument which is not foreign key - it is ingored ... print len(Three.objects.select_related('c')) 10 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id" FROM "tmp_three" >>> >>> # Select related with argument which does not exists - it is ingored ... print len(Three.objects.select_related('nonsense')) 10 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id" FROM "tmp_three" >>> >>> # Select related with argument which is not-null foreign key - inner join is used ... print len(Three.objects.select_related('one')) 10 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id", "tmp_one"."id", "tmp_one"."a" FROM "tmp_three" INNER JOIN "tmp_one" ON ("tmp_three"."one_id" = "tmp_one"."id") >>> >>> # Select related with argument which is null foreign key - inner join is used ... print len(Three.objects.select_related('two')) 5 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id", "tmp_two"."id", "tmp_two"."b" FROM "tmp_three" INNER JOIN "tmp_two" ON ("tmp_three"."two_id" = "tmp_two"."id") >>> >>> # Select related with arguments for both foreign keys - inner joins are used ... print len(Three.objects.select_related('two')) 5 >>> print connection.queries[-1]['sql'] SELECT "tmp_three"."id", "tmp_three"."c", "tmp_three"."one_id", "tmp_three"."two_id", "tmp_two"."id", "tmp_two"."b" FROM "tmp_three" INNER JOIN "tmp_two" ON ("tmp_three"."two_id" = "tmp_two"."id")
Change History (2)
comment:1 by , 17 years ago
comment:2 by , 17 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Note:
See TracTickets
for help on using tickets.
Last example has a mistake, right version: