#26676 closed Bug (fixed)
Prefetch with to_attr shouldn't store its result in the referenced relation cache
| Reported by: | Arnaud B | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.10 |
| Severity: | Release blocker | Keywords: | Prefetch prefetch_related queryset |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When using prefetch_related with a Prefetch whose to_attr is set, the related object returns a list instead of a queryset, making chaining queries impossible. This bug affects both version 1.9 and 1.10, but to a different extent.
This minimal example illustrates the issue, the test fails with AttributeError: 'list' object has no attribute 'filter'
model'
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=12)
class Page(models.Model):
number = models.SmallIntegerField()
text = models.TextField()
book = models.ForeignKey(Book)
tests.py
from django.test import TestCase
from alpha_test.models import Book, Page
from django.db.models import Q, Prefetch
class SimpleCase(TestCase):
def setUp(self):
book = Book.objects.create(name="Django Textbook")
page1 = Page.objects.create(number=1, text="lorem", book=book)
page2 = Page.objects.create(number=2, text="ipsum", book=book)
def test_prefech_related_with_Prefetch(self):
queryset = Page.objects.filter(number=1)
prefetch_no_attr = Prefetch('page_set', queryset=queryset)
prefetch_with_attr = Prefetch('page_set', queryset=queryset,
to_attr='first_page')
# Selecting the book with the Prefetch without to_attr
# it is possible to chain queries on the page_set
book = Book.objects.prefetch_related(prefetch_no_attr).first()
first_page = book.page_set.filter(number=1) # works fine
# Now with Prefetch with to_attr set to some value,
# the same query on page_set fails for 1.10 (but works for 1.9).
book = Book.objects.prefetch_related(prefetch_with_attr).first()
first_page = book.page_set.filter(number=1)
# However, querying on the to_attr fails for both 1.9 and 1.10
first_page = book.first_page.filter(text="lorem")
Change History (5)
comment:1 by , 9 years ago
| Severity: | Normal → Release blocker |
|---|---|
| Summary: | prefetch_related incorrectly returns list instead of queryset when using Prefetch with to_attr → Prefetch with to_attr shouldn't store its result in the referenced relation cache |
| Triage Stage: | Unreviewed → Accepted |
| Version: | master → 1.10 |
comment:3 by , 9 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Note:
See TracTickets
for help on using tickets.
Hi Ursidours,
Thanks for your very detailed report.
As documented, when using
to_attrthe prefetched result is stored in a list. If you'd like to request this to be changed I suggest you open a new ticket for this purpose.Now, using
to_attrshouldn't prefetch and store results for the referenced relation (unless the referenced relation equalsto_attr). It should be left untouched and that's a regression in 1.10 introduced by bdbe50a491ca41e7d4ebace47bfe8abe50a58211.Based on your model definition a simplified test case could look like: