Kaydet (Commit) a2e97abd authored tarafından François Freitag's avatar François Freitag Kaydeden (comit) Tim Graham

Fixed #29159 -- Made ModelChoiceIterator reuse QuerySet result cache.

When __len__() is called (e.g. when casting to list or tuple), the
QuerySet is evaluated and the result cache populated. iterator()
shouldn't be called on the QuerySet after that, as it would reset the
result cache and trigger a second query.
üst 40f0aa98
...@@ -1132,7 +1132,7 @@ class ModelChoiceIterator: ...@@ -1132,7 +1132,7 @@ class ModelChoiceIterator:
yield ("", self.field.empty_label) yield ("", self.field.empty_label)
queryset = self.queryset queryset = self.queryset
# Can't use iterator() when queryset uses prefetch_related() # Can't use iterator() when queryset uses prefetch_related()
if not queryset._prefetch_related_lookups: if not queryset._prefetch_related_lookups and queryset._result_cache is None:
queryset = queryset.iterator() queryset = queryset.iterator()
for obj in queryset: for obj in queryset:
yield self.choice(obj) yield self.choice(obj)
......
...@@ -257,6 +257,17 @@ class ModelChoiceFieldTests(TestCase): ...@@ -257,6 +257,17 @@ class ModelChoiceFieldTests(TestCase):
(self.c3.pk, 'Third'), (self.c3.pk, 'Third'),
]) ])
def test_queryset_result_cache_is_reused(self):
f = forms.ModelChoiceField(Category.objects.all())
with self.assertNumQueries(1):
# list() calls __len__() and __iter__(); no duplicate queries.
self.assertEqual(list(f.choices), [
('', '---------'),
(self.c1.pk, 'Entertainment'),
(self.c2.pk, 'A test'),
(self.c3.pk, 'Third'),
])
def test_num_queries(self): def test_num_queries(self):
""" """
Widgets that render multiple subwidgets shouldn't make more than one Widgets that render multiple subwidgets shouldn't make more than one
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment