summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Plant <L.Plant.98@cantab.net>2013-05-24 10:01:34 +0100
committerLuke Plant <L.Plant.98@cantab.net>2013-05-24 11:10:48 +0100
commit4fd94969d859eb25680a5a52ed482c8f22e5ee15 (patch)
tree2d1f4c32ccb06d03aab19e212b966e230ed4d836
parent48424adaba74379eee311b3d1519f011212357ad (diff)
Fixed #19607 - prefetch_related crash
Thanks to av@rdf.ru and flarno11@yahoo.de for the report.
-rw-r--r--django/db/models/query.py9
-rw-r--r--tests/prefetch_related/models.py20
-rw-r--r--tests/prefetch_related/tests.py25
3 files changed, 51 insertions, 3 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index b2ffa32004..53ee999d0d 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.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
diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py
index 81c569844f..82bf85e401 100644
--- a/tests/prefetch_related/models.py
+++ b/tests/prefetch_related/models.py
@@ -195,3 +195,23 @@ class Employee(models.Model):
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)
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index e81560f01f..3921153246 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -8,7 +8,8 @@ from django.utils import six
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 @@ class MultiDbTests(TestCase):
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'))