Opened 10 years ago

Closed 10 years ago

Last modified 10 years ago

#22650 closed Bug (fixed)

Regression from f51c1f59 with select_related + prefetch_related

Reported by: Aymeric Augustin Owned by: loic84
Component: Database layer (models, ORM) Version: 1.7-beta-2
Severity: Release blocker Keywords:
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

If a queryset does:

  • 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:

  • tests/prefetch_related/models.py

    diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py
    index 8fec5d4..ef2eeb7 100644
    a b class BookWithYear(Book):  
    6666        AuthorWithAge, related_name='books_with_year')
    6767
    6868
     69class Bio(models.Model):
     70    author = models.OneToOneField(Author)
     71    books = models.ManyToManyField(Book, blank=True)
     72
     73
    6974@python_2_unicode_compatible
    7075class Reader(models.Model):
    7176    name = models.CharField(max_length=50)
  • tests/prefetch_related/tests.py

    diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
    index 6732e45..0cdd8db 100644
    a b from django.test import TestCase, override_settings  
    99from django.utils import six
    1010from django.utils.encoding import force_text
    1111
    12 from .models import (Author, Book, Reader, Qualification, Teacher, Department,
     12from .models import (Author, Bio, Book, Reader, Qualification, Teacher, Department,
    1313    TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
    1414    BookWithYear, BookReview, Person, House, Room, Employee, Comment,
    1515    LessonEntry, WordEntry, Author2)
    class PrefetchRelatedTests(TestCase):  
    192192                                     ["Amy"],
    193193                                     ["Amy", "Belinda"]])
    194194
     195    def test_reverse_one_to_one_then_m2m(self):
     196        list(Author.objects.prefetch_related('bio__books').select_related('bio'))
     197
    195198    def test_attribute_error(self):
    196199        qs = Reader.objects.all().prefetch_related('books_read__xyz')
    197200        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.

Change History (10)

comment:1 by loic84, 10 years ago

Owner: changed from nobody to loic84
Status: newassigned

comment:2 by Tim Graham, 10 years ago

Version: master1.7-beta-2

comment:4 by Tim Graham, 10 years ago

Triage Stage: AcceptedReady for checkin

comment:5 by Tim Graham, 10 years ago

Patch needs improvement: set
Triage Stage: Ready for checkinAccepted

Actually tests don't pass on Python 3.

comment:6 by Tim Graham, 10 years ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:7 by Loic Bistuer <loic.bistuer@…>, 10 years ago

Resolution: fixed
Status: assignedclosed

In 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('biobooks')

Thanks Aymeric Augustin for the report and tests. Refs #17001.

comment:8 by Loic Bistuer <loic.bistuer@…>, 10 years ago

In 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.

comment:9 by Loic Bistuer <loic.bistuer@…>, 10 years ago

In 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('biobooks')

Thanks Aymeric Augustin for the report and tests. Refs #17001.

Backport of bdf3473e64 from master

comment:10 by Loic Bistuer <loic.bistuer@…>, 10 years ago

In 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

Note: See TracTickets for help on using tickets.
Back to Top