Changes between Version 1 and Version 2 of Ticket #31295, comment 3
- Timestamp:
- Feb 26, 2020, 1:58:29 AM (5 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Ticket #31295, comment 3
v1 v2 11 11 my_form = MyForm() 12 12 type(my_form.widget.choices) 13 # >>> return <class 'django.forms.models.ModelChoiceIterator'> 13 # >>> return <class 'django.forms.models.ModelChoiceIterator'> and not <list> 14 14 15 15 my_form.as_ul() … … 19 19 20 20 Here is what I understand: 21 1. The code you sent, where {{{ChoiceWidget.choices}}} is evaluated and saved into a {{{list}}} is executed at the initialization of the widget (which is executed at the initialization of the field at the declaration of the form).22 2. But! a {{{ModelChoiceField}}} override {{{self.choices}}} [https://github.com/django/django/blob/271fdab8b78af558238df51c64b4d1c8dd0792bb/django/forms/models.py#L1225-L1227 here] (it makes perfect sense: the choices have to be evaluatedeverytime the form is instanciated).23 3. As the choices are bundled in a {{{ModelChoiceIterator}}}/{{{.iterator()}}}, when rendering the form, there is a test about the {{{required}}} attributethat try to [https://github.com/django/django/blob/ffcf1a8ebfbdc8e3afac84aed88d6ed29a57c72b/django/forms/widgets.py#L699 fetch the first value of the queryset]:21 1. The code you sent, where {{{ChoiceWidget.choices}}} is evaluated and saved into a {{{list}}}, is executed at the initialization of the widget (which is executed at the initialization of the field at the declaration of the form). 22 2. But! a {{{ModelChoiceField}}} override {{{self.choices}}} [https://github.com/django/django/blob/271fdab8b78af558238df51c64b4d1c8dd0792bb/django/forms/models.py#L1225-L1227 here] (it makes sense: the choices have to be queried from the database everytime the form is instanciated). 23 3. When rendering the form, there is a test about the {{{required}}} attribute (for valid HTML rendering from the comment) that try to [https://github.com/django/django/blob/ffcf1a8ebfbdc8e3afac84aed88d6ed29a57c72b/django/forms/widgets.py#L699 fetch the first value of the queryset]: 24 24 {{{#!python 25 25 class Select(ChoiceWidget): … … 29 29 first_choice = next(iter(self.choices), None) 30 30 }}} 31 4. {{{ModelChoiceIterator.__iter__}}} [https://github.com/django/django/blob/ffcf1a8ebfbdc8e3afac84aed88d6ed29a57c72b/django/forms/models.py#L1148-L1156 is called]. If {{{empty_label}}} is not {{{None}}}, everything is fine, as the {{{next()}}} grabs the empty label, without additional request to the database. But if {{{empty_label}}} is {{{None}}} (and if there is no prefetch to the queryset), an additional request is made (code is changed lightly to illustrate the bug) :31 4. {{{ModelChoiceIterator.__iter__}}} [https://github.com/django/django/blob/ffcf1a8ebfbdc8e3afac84aed88d6ed29a57c72b/django/forms/models.py#L1148-L1156 is called]. If {{{empty_label}}} is not {{{None}}}, everything is fine, as the {{{next()}}} grabs the empty label, without additional request to the database. But if {{{empty_label}}} is {{{None}}} (and if there is no prefetch to the queryset), an additional request is made (code is changed lightly to illustrate the bug) because the queryset was not cached (due to {{{.iterator()}}}): 32 32 {{{#!python 33 33 def __iter__(self):