Ryan Skene
Ryan Skene

Reputation: 924

Django model objects do not load in Form in testing environment

Using Django 2.1.3

Getting a strange error here; I have a form multiplechoicefield that draws its choices from the values existing in a model in the database.

class ChartForm(Form):
    P_CHOICES = tuple((p["p"], p["p"]) for p in VAR.objects.all().values("p"))

    p = MultipleChoiceField(widget=CheckboxSelectMultiple, choices=P_CHOICES, initial=P_CHOICES[0][1])

I am trying to run tests for a different app in the project. It throws the following error:

  File "/code/pyyc/forms.py", line 31, in ChartForm
    p = MultipleChoiceField(widget=CheckboxSelectMultiple, choices=P_CHOICES, initial=P_CHOICES[0][1])
IndexError: tuple index out of range

I assumed it was just because the model objects weren't loaded. So I added in the fixtures from the VAR app.

And yet, it still throws the error. Presumably, the Form is render before the test database is compiled ... ?

So I am now editing the Form so that P_CHOICES is done manually, but this is obviously not ideal for the test environment.

Anyone ever come across this? Is there a smart hack for this that doesn't involve commenting out lines in the Form every time you want to test?

Upvotes: 0

Views: 38

Answers (1)

Will Keeling
Will Keeling

Reputation: 23044

Your presumption I think is correct. The class level attribute P_CHOICES is created when Python first loads the ChartForm class, before the test has actually started running. The fixtures are installed later as part of the test's setUpClass() (called by the test framework) but by that point P_CHOICES has already been defined and is empty.

You could try creating the MultipleChoiceField without its choices and initial attributes, and then set those in the form's __init__ when the data is available. For example:

class ChartForm(Form):
    p = MultipleChoiceField(widget=CheckboxSelectMultiple)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        p_choices = tuple((p["p"], p["p"]) for p in VAR.objects.all().values("p"))
        # Now we have the data we can set the attributes
        self.fields['p'].choices = p_choices
        self.fields['p'].initial = p_choices[0][1]

Upvotes: 1

Related Questions