使用 ModelChoiceView 时处理 POST 请求

Handling POST request when using ModelChoiceView

我的简单表单如下所示:

class PropertyFilterForm(forms.Form):
    property_type = forms.ModelChoiceField(queryset=Property.objects.values_list('type', flat=True).order_by().distinct())

property_type returns 我模板中下拉列表的字符串值的平面列表。

现在,当我选择其中一个值并点击 "Submit" - 我收到以下错误:

Select a valid choice. That choice is not one of the available choices.

我现在的观点是这样的:

def index(request):
    if request.method == 'POST':
        form = PropertyFilterForm(request.POST)
        if form.is_valid():
            selected_type = form.cleaned_data['property_type']
            properties = Property.objects.filter(type=selected_type)
    else:
        form = PropertyFilterForm()
        properties = Property.objects.all()
    return render(request, 'index.html',  context=locals())

我读了又读 this question 很多遍。好像是一样的,但是我还是没能想出确切的解决办法。

到目前为止我的理解是,我需要在每次在视图中调用时为我的表单显式指定一个查询集,或者(更好)在我的表单的 init 方法中指定查询集。

能否请有人详细说明我们是否需要按照我上面描述的方式指定查询集?

如果是,为什么?我们不是已经在表单定义中指定了吗?

如果有任何代码片段,我将不胜感激

您希望用户 select 一个字符串,而不是 属性 实例,所以我认为使用 ChoiceField 而不是 [=15] 更合适=].

class PropertyFilterForm(forms.Form):
    property_type = forms.ChoiceField(choices=[])

    def __init__(self, *args, **kwargs):
        super(PropertyFilterForm, self).__init__(*args, **kwargs)
        self.fields['property_type'].choices = Property.objects.values_list('type', 'type').order_by('type').distinct()

使用 ChoiceField 的缺点是我们需要在表单的 __init__ 方法中生成选项。我们失去了 ModelChoiceField 的良好功能,每次创建表单时都会评估查询集。

我不清楚为什么 Daniel 建议坚持使用 ModelChoiceField 而不是 ChoiceField。如果您要使用 ModelChoiceField,我认为您必须将其子类化并覆盖 label_from_instance。据我所知,使用 values() 是行不通的。

要指定初始值,您可以在表单定义中对其进行硬编码,

class PropertyFilterForm(forms.Form):
    property_type = forms.ChoiceField(choices=[], initial='initial_type')

或者在__init__方法中设置,

self.fields['property_type'].initial = 'initial_type'

或者在实例化表单时提供:

    form = PropertyFilterForm(request.POST, initial={'property_type': 'initial_type'})