- select_related through a reverse one-to-one
- prefetch_related through that one-to-one then another relation
and some objects don't have a related object through the reverse one-to-
one, iterating the queryset raises an exception.
This is easier to demonstrate with a test case:
{{{#!diff
diff --git a/tests/prefetch_related/models.py
b/tests/prefetch_related/models.py
index 8fec5d4..ef2eeb7 100644
--- a/tests/prefetch_related/models.py
+++ b/tests/prefetch_related/models.py
@@ -66,6 +66,11 @@ class BookWithYear(Book):
AuthorWithAge, related_name='books_with_year')
+class Bio(models.Model):
+ author = models.OneToOneField(Author)
+ books = models.ManyToManyField(Book, blank=True)
+
+
@python_2_unicode_compatible
class Reader(models.Model):
name = models.CharField(max_length=50)
diff --git a/tests/prefetch_related/tests.py
b/tests/prefetch_related/tests.py
index 6732e45..0cdd8db 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -9,7 +9,7 @@ from django.test import TestCase, override_settings
from django.utils import six
from django.utils.encoding import force_text
-from .models import (Author, Book, Reader, Qualification, Teacher,
Department,
+from .models import (Author, Bio, Book, Reader, Qualification, Teacher,
Department,
TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
BookWithYear, BookReview, Person, House, Room, Employee, Comment,
LessonEntry, WordEntry, Author2)
@@ -192,6 +192,9 @@ class PrefetchRelatedTests(TestCase):
["Amy"],
["Amy", "Belinda"]])
+ def test_reverse_one_to_one_then_m2m(self):
+
list(Author.objects.prefetch_related('bio__books').select_related('bio'))
+
def test_attribute_error(self):
qs = Reader.objects.all().prefetch_related('books_read__xyz')
with self.assertRaises(AttributeError) as cm:
}}}
This test fails with:
{{{
Traceback (most recent call last):
File "/Users/myk/Documents/dev/django/tests/prefetch_related/tests.py",
line 196, in test_reverse_one_to_one_then_m2m
list(Author.objects.prefetch_related('bio__books').select_related('bio'))
File "/Users/myk/Documents/dev/django/django/db/models/query.py", line
141, in __iter__
self._fetch_all()
File "/Users/myk/Documents/dev/django/django/db/models/query.py", line
965, in _fetch_all
self._prefetch_related_objects()
File "/Users/myk/Documents/dev/django/django/db/models/query.py", line
608, in _prefetch_related_objects
prefetch_related_objects(self._result_cache,
self._prefetch_related_lookups)
File "/Users/myk/Documents/dev/django/django/db/models/query.py", line
1793, in prefetch_related_objects
elif isinstance(getattr(first_obj, through_attr), list):
File
"/Users/myk/Documents/dev/django/django/db/models/fields/related.py", line
420, in __get__
self.related.get_accessor_name()
RelatedObjectDoesNotExist: Author has no bio.
}}}
The regression exists in master and 1.7.x.
--
Ticket URL: <https://code.djangoproject.com/ticket/22650>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* owner: nobody => loic84
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:1>
* version: master => 1.7-beta-2
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:2>
* has_patch: 0 => 1
Comment:
PR https://github.com/django/django/pull/2681.
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:3>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:4>
* needs_better_patch: 0 => 1
* stage: Ready for checkin => Accepted
Comment:
Actually tests don't pass on Python 3.
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:5>
* needs_better_patch: 1 => 0
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:6>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"bdf3473e64879d196e79fe8832cdacc6efb68150"]:
{{{
#!CommitTicketReference repository=""
revision="bdf3473e64879d196e79fe8832cdacc6efb68150"
Fixed #22650 -- Fixed regression on prefetch_related.
Regression from f51c1f59 when using select_related then prefetch_related
on the reverse side of an O2O:
Author.objects.select_related('bio').prefetch_related('bio__books')
Thanks Aymeric Augustin for the report and tests. Refs #17001.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:7>
Comment (by Loic Bistuer <loic.bistuer@…>):
In [changeset:"870b0a1f8689aa8fd4806623262228b8ac3a88a5"]:
{{{
#!CommitTicketReference repository=""
revision="870b0a1f8689aa8fd4806623262228b8ac3a88a5"
Fixed the ordering of prefetch lookups so that latter lookups can refer to
former lookups.
Thanks Anssi Kääriäinen and Tim Graham for the reviews. Refs #17001 and
#22650.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:8>
Comment (by Loic Bistuer <loic.bistuer@…>):
In [changeset:"0fa1aeb8d8142bd6bceb0c9a36c8e42eeca21770"]:
{{{
#!CommitTicketReference repository=""
revision="0fa1aeb8d8142bd6bceb0c9a36c8e42eeca21770"
[1.7.x] Fixed the ordering of prefetch lookups so that latter lookups can
refer to former lookups.
Thanks Anssi Kääriäinen and Tim Graham for the reviews. Refs #17001 and
#22650.
Backport of 870b0a1f86 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:10>
Comment (by Loic Bistuer <loic.bistuer@…>):
In [changeset:"24a41ecc3590f8d92d085d4a4caa5f8bf962ceae"]:
{{{
#!CommitTicketReference repository=""
revision="24a41ecc3590f8d92d085d4a4caa5f8bf962ceae"
[1.7.x] Fixed #22650 -- Fixed regression on prefetch_related.
Regression from f51c1f59 when using select_related then prefetch_related
on the reverse side of an O2O:
Author.objects.select_related('bio').prefetch_related('bio__books')
Thanks Aymeric Augustin for the report and tests. Refs #17001.
Backport of bdf3473e64 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/22650#comment:9>