Permalink
Browse files

Fixed #19607 - prefetch_related crash

Thanks to av@rdf.ru and flarno11@yahoo.de for the report.
  • Loading branch information...
1 parent 48424ad commit 4fd94969d859eb25680a5a52ed482c8f22e5ee15 @spookylukey spookylukey committed May 24, 2013
Showing with 51 additions and 3 deletions.
  1. +7 −2 django/db/models/query.py
  2. +20 −0 tests/prefetch_related/models.py
  3. +24 −1 tests/prefetch_related/tests.py
@@ -1558,8 +1558,13 @@ def prefetch_related_objects(result_cache, related_lookups):
good_objects = False
break
else:
- # We already did this list
- break
+ # Since prefetching can re-use instances, it is possible to
+ # have the same instance multiple times in obj_list. So we
+ # can reach this branch either because we did all of
+ # obj_list already, or because we did 'obj' earlier in this
+ # iteration over obj_list. In the first case we could
+ # shortcut and exit the loop, but not in the second.
+ continue
if not good_objects:
break
@@ -195,3 +195,23 @@ def __str__(self):
class Meta:
ordering = ['id']
+
+
+### Ticket 19607
+
+@python_2_unicode_compatible
+class LessonEntry(models.Model):
+ name1 = models.CharField(max_length=200)
+ name2 = models.CharField(max_length=200)
+
+ def __str__(self):
+ return "%s %s" % (self.name1, self.name2)
+
+
+@python_2_unicode_compatible
+class WordEntry(models.Model):
+ lesson_entry = models.ForeignKey(LessonEntry)
+ name = models.CharField(max_length=200)
+
+ def __str__(self):
+ return "%s (%s)" % (self.name, self.id)
@@ -8,7 +8,8 @@
from .models import (Author, Book, Reader, Qualification, Teacher, Department,
TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
- BookWithYear, BookReview, Person, House, Room, Employee, Comment)
+ BookWithYear, BookReview, Person, House, Room, Employee, Comment,
+ LessonEntry, WordEntry)
class PrefetchRelatedTests(TestCase):
@@ -618,3 +619,25 @@ def test_using_is_honored_inheritance(self):
ages = ", ".join(str(a.authorwithage.age) for a in A.prefetch_related('authorwithage'))
self.assertEqual(ages, "50, 49")
+
+
+class Ticket19607Tests(TestCase):
+
+ def setUp(self):
+
+ for id, name1, name2 in [
+ (1, 'einfach', 'simple'),
+ (2, 'schwierig', 'difficult'),
+ ]:
+ LessonEntry.objects.create(id=id, name1=name1, name2=name2)
+
+ for id, lesson_entry_id, name in [
+ (1, 1, 'einfach'),
+ (2, 1, 'simple'),
+ (3, 2, 'schwierig'),
+ (4, 2, 'difficult'),
+ ]:
+ WordEntry.objects.create(id=id, lesson_entry_id=lesson_entry_id, name=name)
+
+ def test_bug(self):
+ list(WordEntry.objects.prefetch_related('lesson_entry', 'lesson_entry__wordentry_set'))

3 comments on commit 4fd9496

Owner

timgraham replied Jul 27, 2013

Luke, any objection to backporting to 1.5.x? The cherry pick merges cleanly and the tests pass.

Member

spookylukey replied Jul 27, 2013

Owner

timgraham replied Jul 27, 2013

Thanks Luke, I've backported both commits.

Please sign in to comment.