#18090 closed Bug (fixed)
`prefetch_related` selects entire table when reverse traversing a `OneToOneField`
| Reported by: | Aymeric Augustin | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | 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
This is best demonstrated with an example:
myapp/models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=10)
class Group(models.Model):
users = models.ManyToManyField(User)
class GroupExtra(models.Model):
group = models.OneToOneField(Group)
./manage.py shell
# Let's create 10 users, 5 groups + group_extras.
>>> from myapp.models import *
>>> users = [User.objects.create(name='user %d' % i) for i in range(10)]
>>> groups = [Group.objects.create() for i in range(5)]
>>> for i in range(5):
... groups[i].users = users[i:i + 5]
...
>>> group_extras = [GroupExtra.objects.create(group=groups[i]) for i in range(5)]
# Load an user with his groups and group_extras.
>>> from pprint import pprint
>>> from django.db import connection
>>> connection.queries = []
>>> user = User.objects.prefetch_related('group_set__groupextra').get(name='user 3')
>>> pprint(connection.queries)
[{'sql': u'SELECT "myapp_user"."id", "myapp_user"."name" FROM "myapp_user" WHERE "myapp_user"."name" = user 3 ',
'time': '0.000'},
{'sql': u'SELECT ("myapp_group_users"."user_id") AS "_prefetch_related_val", "myapp_group"."id" FROM "myapp_group" INNER JOIN "myapp_group_users" ON ("myapp_group"."id" = "myapp_group_users"."group_id") WHERE "myapp_group_users"."user_id" IN (4)',
'time': '0.000'},
{'sql': u'SELECT "myapp_groupextra"."id", "myapp_groupextra"."group_id" FROM "myapp_groupextra"',
'time': '0.000'}]
# The last query unnecessarily loaded the entire `myapp_groupextra` table.
# But prefetch_related worked as expected: the following code doesn't trigger another query
>>> connection.queries = []
>>> for group in user.group_set.all():
... print group.pk, group.groupextra.pk
...
1 1
2 2
3 3
4 4
>>> pprint(connection.queries)
[]
Attachments (2)
Change History (5)
by , 14 years ago
| Attachment: | ticket_18090.diff added |
|---|
comment:1 by , 14 years ago
The attached patch is completely untested, but should fix the issue. It was a simple case of forgetting to use the filter parameters.
Since this is a major bug in a new feature (would have been a release blocker), and is extremely unlikely to cause regressions, I think it should be backported to 1.4.X
Note:
See TracTickets
for help on using tickets.
fix