Django根据ModelForm中的ChoiceField选择填充许多

Django根据ModelForm中的ChoiceField选择填充许多,django,many-to-many,django-queryset,Django,Many To Many,Django Queryset,我有一个具有多个关系的类,我想用它来创建应用程序的控制面板: class ControlPanel(models.Model): viewtype = models.CharField("view type", max_length=32, unique=True) choice1 = models.ManyToManyField(Choice1, null=True) choice2 = models.ManyToManyField(Choice2, null=

我有一个具有多个关系的类,我想用它来创建应用程序的控制面板:

class ControlPanel(models.Model):
    viewtype = models.CharField("view type", max_length=32, unique=True)    
    choice1 = models.ManyToManyField(Choice1, null=True)
    choice2 = models.ManyToManyField(Choice2, null=True)
    choice3 = models.ManyToManyField(Choice3, null=True)
其中,
Choice1
Choice2
Choice3
是我希望呈现为复选框的选项
controlpanel_choice1
controlpanel_choice2
controlpanel_choice3
是M2M与
choice1
choice2
choice3
选项之间关系的表格。因此,根据视图类型id,每个
Choice*
集的选项集可能不同(甚至不存在)

我从这个ControlPanel类创建了一个表单来生成我的控制面板:

class ControlPanelForm(ModelForm):
    viewtype = forms.ChoiceField(choices = ControlPanel.objects.values_list('id','view'))
    choice1 = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Choice1.objects.all())
    choice2 = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Choice2.objects.all())
    choice3 = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Choice3.objects.all())

    class Meta:
        model = ControlPanel
这将显示“3选项*精细”字段。但是,它不会将选项限制为每个viewtype选项,因为我的queryset会为每个
选项*
字段显示
.objects.all()
。此外,这将显示对象地址,而不是每个选项的名称字段*。 我该怎么做?我需要为绑定表单和未绑定表单显示选项*。我是否需要在构造函数中构建它们,检查我的表单是否有效,并获取当前选定的viewtype以构建查询集?我可以在我的
控制面板
类中使用此逻辑,并避免在我的视图函数中编程此逻辑吗?我希望能举一些这样做的例子


提前感谢。

首先,您需要创建一个接受参数的表单

class ControlPanelForm(ModelForm):
    class Meta:
        model = ControlPanel
        widgets = {
            'choice1': forms.CheckboxSelectMultiple(),
            'choice2': forms.CheckboxSelectMultiple(),
            'choice3': forms.CheckboxSelectMultiple(),
        }

    def __init__(self, *args, **kwargs):
        viewtype = kwargs.pop('viewtype')
        super(ControlPanelForm, self).__init__(*args, **kwargs)
        self.fields['choice1'].queryset = Choice1.objects.filter( ... )
        self.fields['choice2'].queryset = Choice2.objects.filter( ... )
        self.fields['choice3'].queryset = Choice3.objects.filter( ... )
正如您所看到的,我已经将
viewtype
作为位置参数传递给表单的init,现在您可以使用它创建带有
filter()
的查询集,而不是使用
all()

此外,当使用
模型表单时,无需再次声明表单字段。如果需要更改任何字段的小部件,使用
Meta
类的
widgets
选项似乎更合适

现在,要在视图中使用此表单,只需将
viewtype
作为位置参数传入即可

viewtype = request.POST['viewtype']
form = ControlPanelForm(viewtype=viewtype)

现在你所要做的就是把它放在一个视图中并调用它,每次传入一个不同的
viewtype

仅仅是这个问题的后续:我意识到在客户端使用javascript/jQuery实现这种特性更符合逻辑。事实上,由于HTMl的非持久性,在服务器端使用这种逻辑是非常尴尬和容易出错的。我在学习基本jQuery方面没有太多困难,并且有一个很好的方法在浏览器端隐藏/显示选项和结果。

Hi,非常感谢这些指针,非常有用。如果我想要viewtype有一个默认值(当有一个未绑定的表单时),我应该在视图中传递这个值,还是可以在ControlPanelForm类中声明它?我已经尝试了你的建议,开始明白了!如果我理解得很好,就无法访问ModelForm实例(?)中小部件的选定值,因此我必须将其作为位置参数传递。我还理解viewtype=kwargs.pop('viewtype')只是从ModelForm的init中删除了一个无效参数。此外,我可以使用另一个名称(如viewnb)弹出参数,并将此变量用于过滤器。保留所有相同的名称很方便。这是否正确?因此,对于默认视图值,我刚刚测试了request.POST.has_key('viewtype')。如果没有,那么表单将使用默认值实例化,并且我在构造函数中传递viewtype={'viewtype':'1'},在创建表单时,“1”是我的默认值(如果访问带有表单的页面时根本没有POST,我可以使用request.method='POST'测试)。当您说您已经测试了请求以查看它是否包含
viewtype
时,这是否意味着每次用户选择一个viewtype时,整个页面都会刷新?不,如果这是您的意思,我还没有试验过AJAX部分。用户更改viewtype后需要提交新表单。这一点我将在以后实现。