diff --git a/django/db/models/query.py b/django/db/models/query.py
index 41c24c7..6ae0a52 100644
a
|
b
|
class QuerySet(object):
|
82 | 82 | if self._iter: |
83 | 83 | self._result_cache = list(self._iter) |
84 | 84 | else: |
85 | | self._result_cache = list(self.iterator()) |
| 85 | self._result_cache = list(self.iterator(_check_prefetch=False)) |
86 | 86 | elif self._iter: |
87 | 87 | self._result_cache.extend(self._iter) |
88 | 88 | if self._prefetch_related_lookups and not self._prefetch_done: |
… |
… |
class QuerySet(object):
|
228 | 228 | # METHODS THAT DO DATABASE QUERIES # |
229 | 229 | #################################### |
230 | 230 | |
231 | | def iterator(self): |
| 231 | def iterator(self, _check_prefetch=True): |
232 | 232 | """ |
233 | 233 | An iterator over the results from applying this QuerySet to the |
234 | 234 | database. |
| 235 | |
| 236 | Calling this method with _check_prefetch=True will cause an error |
| 237 | if there are prefetches defined for the qs. Internal methods can |
| 238 | skip prefetch_related checks by defining _check_prefetch=False. |
235 | 239 | """ |
| 240 | if _check_prefetch and self._prefetch_related_lookups: |
| 241 | raise ValueError("Using iterator() when prefetch_related is used " |
| 242 | "is not supported") |
236 | 243 | fill_cache = False |
237 | 244 | if connections[self.db].features.supports_select_related: |
238 | 245 | fill_cache = self.query.select_related |
… |
… |
class QuerySet(object):
|
485 | 492 | qs = self._clone() |
486 | 493 | qs.query.add_filter(('pk__in', id_list)) |
487 | 494 | qs.query.clear_ordering(force_empty=True) |
488 | | return dict([(obj._get_pk_val(), obj) for obj in qs.iterator()]) |
| 495 | # Populate the query, making sure prefetch_related etc. are handled |
| 496 | # properly. |
| 497 | objs = list(self) |
| 498 | return dict([(obj._get_pk_val(), obj) for obj in objs]) |
489 | 499 | |
490 | 500 | def delete(self): |
491 | 501 | """ |
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 103cae1..725f38d 100644
a
|
b
|
performance and a significant reduction in memory.
|
1430 | 1430 | Note that using ``iterator()`` on a ``QuerySet`` which has already been |
1431 | 1431 | evaluated will force it to evaluate again, repeating the query. |
1432 | 1432 | |
| 1433 | It is an error to use ``iterator()`` when ``prefetch_related`` is also used |
| 1434 | in the same ``QuerySet``. |
| 1435 | |
1433 | 1436 | latest |
1434 | 1437 | ~~~~~~ |
1435 | 1438 | |
diff --git a/tests/modeltests/prefetch_related/tests.py b/tests/modeltests/prefetch_related/tests.py
index 4c51a83..f457fc9 100644
a
|
b
|
class NullableTest(TestCase):
|
470 | 470 | for e in qs2] |
471 | 471 | |
472 | 472 | self.assertEqual(co_serfs, co_serfs2) |
| 473 | |
| 474 | class TestIterator(TestCase): |
| 475 | |
| 476 | def test_iterator_raises_error(self): |
| 477 | """ |
| 478 | Using an iterator when prefetch_related is defined is an error. |
| 479 | """ |
| 480 | def raises(): |
| 481 | list(Employee.objects.prefetch_related('boss').iterator()) |
| 482 | self.assertRaises(ValueError, raises) |
| 483 | |
| 484 | def test_in_bulk(self): |
| 485 | """ |
| 486 | In-bulk does correctly prefetch objects by not using .iterator() |
| 487 | directly. |
| 488 | """ |
| 489 | boss = Employee.objects.create(name="Peter") |
| 490 | boss = Employee.objects.create(name="Jack") |
| 491 | with self.assertNumQueries(2): |
| 492 | # Check that prefetch is done and it does not cause any errors. |
| 493 | bulk = Employee.objects.prefetch_related('serfs').in_bulk([boss.pk]) |
| 494 | for b in bulk.values(): |
| 495 | list(b.serfs.all()) |