Opened 4 years ago

Closed 4 years ago

#31961 closed Bug (duplicate)

forms.ChoiceField calls choices callback multiple times.

Reported by: Roy Smith Owned by: nobody
Component: Forms Version: 2.2
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Roy Smith)

I'm running:

Python 3.7
Django 2.2
Debian 4.9

If I configure a forms ChoiceField with a callback function for choices, it gets called twice each time I render the form:

from unittest import TestCase
from django import forms

def callback():
    print("callback")
    return [('foo', 'bar')]

class MyForm(forms.Form):
    f = forms.ChoiceField(choices=callback)


class FormTest(TestCase):
    MyForm().as_p()

prints:

./manage.py test spi.test_f
callback
callback
System check identified no issues (0 silenced).

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

This is the same sort of problem described in #26665 and/or #11390. It's an obvious performance issue, but more than that, it can beak behavior if the callback is non-idempotent.

I discovered this because I had patched my callback using unttest.mock to return a sequence of return values and got hard-to-diagnose test failures. Specifically, my test failed because it raised StopIteration when it ran out of values to return.

Change History (5)

comment:1 by Roy Smith, 4 years ago

Description: modified (diff)

comment:2 by Roy Smith, 4 years ago

fixed typo

comment:3 by Carlton Gibson, 4 years ago

Hi Roy.

Thanks for the report. Short of a concrete suggestion here, I’m struggling to see how this isn’t just a duplicate of #11390.

The conclusion there seems unchanged:

...I'm not sure how or if it's possible to combine the two remaining calls...
One's the in memory model being instantiated and the other's the ModelForm field/widget populating it's values. They seem separate and I'm not sure where any memoisation of this value would go or if it would be a great idea.

Russel’s initial reply seems the appropriate workaround.

What would be your thought there?

comment:4 by Roy Smith, 4 years ago

I'm not familiar with the django code internals, so I can't make any concrete suggestions about how to fix it. At the very least, however, it should be documented.

comment:5 by Carlton Gibson, 4 years ago

Resolution: duplicate
Status: newclosed

Let's close as a duplicate of #11390.

The ChoiceField docs already mention the evaluation during the form initialization. I've opened a PR with a possible clarification.

Note: See TracTickets for help on using tickets.
Back to Top