Changes between Version 1 and Version 2 of Ticket #31295, comment 3


Ignore:
Timestamp:
Feb 26, 2020, 1:58:29 AM (4 years ago)
Author:
Aurélien Pardon

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #31295, comment 3

    v1 v2  
    1111my_form = MyForm()
    1212type(my_form.widget.choices)
    13 # >>> return <class 'django.forms.models.ModelChoiceIterator'>
     13# >>> return <class 'django.forms.models.ModelChoiceIterator'> and not <list>
    1414
    1515my_form.as_ul()
     
    1919
    2020Here 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 evaluated everytime 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}}} attribute that try to [https://github.com/django/django/blob/ffcf1a8ebfbdc8e3afac84aed88d6ed29a57c72b/django/forms/widgets.py#L699 fetch the first value of the queryset]:
     211. 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).
     222. 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).
     233. 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]:
    2424{{{#!python
    2525class Select(ChoiceWidget):
     
    2929        first_choice = next(iter(self.choices), None)
    3030}}}
    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):
     314. {{{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()}}}):
    3232{{{#!python
    3333    def __iter__(self):
Back to Top