#29159: ModelChoiceIterator triggers duplicate queries when choices are cast to
list
-------------------------------------+-------------------------------------
               Reporter:  François   |          Owner:  François Freitag
  Freitag                            |
                   Type:             |         Status:  assigned
  Uncategorized                      |
              Component:  Forms      |        Version:  1.8
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 When there are no `prefetch_related()` on `ModelChoiceIterator`'s
 queryset, it attempts to use the `iterator()` method to avoid loading all
 choices in memory.
 ([https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-
 related because iterator() and prefetch_related() don't make sense
 together.])

 That results in a duplicate query if the choices have been evaluated
 before, because calling `iterator()` will clone the `QuerySet`, resetting
 its result cache in the process.

 {{{
 class TestModelChoiceField(TestCase):
     def test_queryset_result_cache_is_reused(self):
         choice = ChoiceOptionModel.objects.create(name="choice 1")
         f = ModelChoiceField(ChoiceOptionModel.objects.all())
         with self.assertNumQueries(1):
             self.assertEqual(
                 # list calls both __len__ and __iter__
                 list(f.choices),
                 [('', '---------'), (choice.pk, str(choice))],
             )
 }}}


 Fails with:
 {{{
 FAIL: test_queryset_result_cache_is_reused
 (forms_tests.test_tmp.TestModelChoiceField)
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File "django/tests/forms_tests/test_tmp.py", line 19, in
 test_queryset_result_cache_is_reused
     [('', '---------'), (choice.pk, str(choice))],
   File "django/django/test/testcases.py", line 80, in __exit__
     '%d. %s' % (i, query['sql']) for i, query in
 enumerate(self.captured_queries, start=1)
 AssertionError: 2 != 1 : 2 queries executed, 1 expected
 Captured queries were:
 1. SELECT "forms_tests_choiceoptionmodel"."id",
 "forms_tests_choiceoptionmodel"."name" FROM
 "forms_tests_choiceoptionmodel" ORDER BY
 "forms_tests_choiceoptionmodel"."name" ASC
 2. SELECT "forms_tests_choiceoptionmodel"."id",
 "forms_tests_choiceoptionmodel"."name" FROM
 "forms_tests_choiceoptionmodel" ORDER BY
 "forms_tests_choiceoption$odel"."name" ASC
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29159>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/058.cd5424752a3841a0c5ec1990d7f86660%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to