如何动态设置forms.Form子类中models.ModelChoiceField的queryset

36 投票
2 回答
21561 浏览
提问于 2025-04-16 11:07

forms.ModelChoiceField的构造函数需要一个查询集(queryset)。但是我在请求发生之前并不知道这个查询集是什么。简单来说就是:

# 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='??????')

我现在的做法是:

# 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

然后我可以在视图中使用从网址中解析出来的参数,结合url配置来构建查询集并获取类。这样做让我觉得不太对劲。有没有更好的方法在Django中实现这个?

2 个回答

17

你也可以在显示表单之前,在你的视图里处理这些事情。我用这种方法,觉得更灵活,因为如果你在其他视图中重用这个表单,每次都需要更改查询集时,这样做会更方便:

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)

我还在forms.py文件中把默认的查询集设置为None:

class AsssetSelectForm(forms.Form):
    asset = forms.ModelChoiceField(queryset=Asset.objects.none())
78

重写表单的 __init__ 方法,并在这里设置查询集。

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

撰写回答