Changing queryset of a ModelChoiceField

July 17, 2010

Sometimes there's a need to change the queryset used in a ModelChoiceField at runtime. This can be done by overriding the init function on the form:

class ResultsForm(forms.Form):
    event_1 = forms.ModelChoiceField(queryset=Contest.objects.none(), required=True)
    event_2 = forms.ModelChoiceField(queryset=Contest.objects.none(), required=False)
    event_3 = forms.ModelChoiceField(queryset=Contest.objects.none(), required=False)

    def __init__(self, pContestGroup, *args, **kwargs):
        super(ResultsForm, self).__init__(*args, **kwargs)
        self.fields['event_1'].queryset = Contest.objects.filter(group=pContestGroup)
        self.fields['event_2'].queryset = Contest.objects.filter(group=pContestGroup)
        self.fields['event_3'].queryset = Contest.objects.filter(group=pContestGroup)

This example code adds another parameter (pContestGroup) to the init function and uses it to limit the list of Contest objects shown in the ModelChoiceField.

To use this in the views.py, simply pass a ContestGroup instance in:

lForm = ResultsForm(lContestGroup)

or

lForm = ResultsForm(lContestGroup, request.POST)

References