How to dynamically set the queryset of a models.ModelChoiceField on a forms.Form subclass

Question:

The constructor for forms.ModelChoiceField requires a queryset. I do not know the queryset until the request happens. Distilled:

# models.py
class Bar(models.model):
    text = models.TextField()

class Foo(models.Model):
    name = models.CharField()
    bar = models.ForeignKey(Bar)

# forms.py
class FooForm(forms.Form):
    name = forms.CharField()
    text = forms.CharField(widget=forms.TextArea)

    bar = forms.ModelChoiceField(queryset='??????')

What I am currently doing:

# forms.py

def get_foo_form_class(bars_queryset):
    class FooForm(forms.Form):
        name = forms.CharField()
        text = forms.CharField(widget=forms.TextArea)

        bar = forms.ModelChoiceField(queryset=bars_queryset)

    return FooForm

I can then call it in the view using arguments parsed out of the url with a urlconf to construct the queryset and get the class. This feels like the wrong way to do it. Is there an established way to do this in django?

Asked By: knucklebumpler

||

Answers:

Override the form’s __init__ method and set the queryset there.

class FooForm(forms.Form):
    bar = forms.ModelChoiceField(queryset=Bar.objects.none())

    def __init__(self, *args, **kwargs):
        qs = kwargs.pop('bars')
        super(FooForm, self).__init__(*args, **kwargs)
        self.fields['bar'].queryset = qs
Answered By: Daniel Roseman

You can also do it in your view before you present the form in the template. I use this and find it more flexible incase you re-use the form in other views and need to change the queryset each time:

from assets.models import Asset
location_id = '123456'
edit_form = AsssetSelectForm(request.POST or None, instance=selected_asset)
edit_form.fields["asset"].queryset = Asset.objects.filter(location_id=location_id)

I also set the default queryset to none in the forms.py:

class AsssetSelectForm(forms.Form):
    asset = forms.ModelChoiceField(queryset=Asset.objects.none())
Answered By: radtek
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.