我有一个Car模型,希望通过相互依赖的ModelChoiceField进行过滤:

class Car(models.Model):
    make = models.CharField(max_length=50)
    model = models.CharField(max_length=50)
    platform = models.CharField(max_length=50)


Forms.py:

class MakeSelectForm(forms.ModelForm):
    make = forms.ModelChoiceField(queryset=Car.objects.values_list('make',flat=True).distinct())
    class Meta:
        model = Car
        fields = ["make"]

class ModelSelectForm(forms.ModelForm):
    model = forms.ModelChoiceField(queryset=Car.objects.values_list('model',flat=True).distinct())
    class Meta:
        model = Car
        fields = ["make", "model"]


Views.py:

def make_select_view(request):
    form = MakeSelectForm()
    make = None
    if request.method == "POST":
        form = MakeSelectForm(request.POST)
        if form.is_valid():
            make = form.cleaned_data['make']
    return render(request, "reviews/makeselect.html", {"form": form, "make": make})

def model_select_view(request, make):
    form = ModelSelectForm()
    model = None
    if request.method == "POST":
        form = MakeSelectForm(request.POST)
        if form.is_valid():
            model = form.cleaned_data['model']
    return render(request, "reviews/modelselect.html", {"form": form, "model": model})


网址:

urlpatterns = [
    url(r'^$', views.make_select_view, name="make-select"),
    url(r'^(?P<make>\w+)/$', views.model_select_view, name="model-select"),
]


Makeselect.html:

<form action="{% url 'reviews:model-select' make %}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Select" />
</form>


现在,我必须将发布时第一个表单的“ make”参数传递给第二个视图,然后使用它来过滤具有该make的Car实例。但是,这里我所传递的只是“无”,并获得选择一个有效的选择。该选择不是可用的选择之一。第二种形式的错误。

任何建议或反馈都将受到欢迎和赞赏。

谢谢。

最佳答案

第一点:模型表单用于创建/编辑模型,因此您应在此处使用普通表单。您的错误来自make字段中的ModelSelectForm字段,但未在任何地方设置其值。另外,ModelChoiceField用于检索模型实例,而不是字段的值,因此,您在这里确实需要ChoiceField

第二点,由于您的目标是显示经过过滤的信息(而不是创建或编辑任何内容),因此应使用GET查询(实际上是针对任何“搜索”功能的)。

为了使第二个表单按预期工作(一旦通过单个Form字段移植到普通的model),则需要将make值传递给该表单,并在该表单的__init__()中进行更新model字段选择过滤后的查询集。

另外,由于您将使用GET作为表单的方法,因此在决定使用或不包含request.GET数据进行实例化之前,必须检查表单是否已提交,否则用户将收到错误消息。在他们还没有机会提交任何东西之前先进行展示。通常可以使用表单提交按钮的名称和值或表单本身中的隐藏字段来解决此问题:

形式:

class  ModelSelectForm(forms.Form):
    model = forms.ChoiceField()

    def __init__(self, *args, **kwargs):
        make = kwargs.pop("make", None)
        if not make:
            raise ValueError("expected a 'make' keyword arg")
        super(ModelSelectForm, self).__init__(*args, **kwargs)
        qs = Car.objects.filter(make=make).values_list('model',flat=True).distinct()
        choices = [(value, value) for value in qs]
        self.fields["model"].choices = choices


观看次数:

def model_select_view(request, make):
    model = None
    if request.GET.get("submitted", None):
        form = ModelSelectForm(request.GET, make=make)
        if form.is_valid():
            model = form.cleaned_data['model']
    else:
        form = ModelSelectForm(make=make)
    context = {"form": form, "model": model, "make: make}
    return render(request, "reviews/modelselect.html", context)


范本:

<form action="{% url 'reviews:model-select' make %}" method="GET">
    {% csrf_token %}
    <input type="hidden" name="submitted" value="1" />
    {{ form.as_p }}
    <input type="submit" value="Select" />
</form>


wrt /有关“将'make'传递到第二个视图”的问题:您的代码段中没有将用户定向到model-select视图的地方,但是我假设您想要的是用户一旦被重定向到该视图在第一个视图中成功选择了“ make”。如果是,则您的第一个视图的代码应处理成功提交表单的情况,即:

def make_select_view(request):
    if request.GET.get("submitted", None):
        form = MakeSelectForm(request.GET)
        if form.is_valid():
            make = form.cleaned_data['make']
            # send the user to the model selection view
            return redirect("reviews:model-select", make=make)

    else:
        form = MakeSelectForm()
    context = {"form": form}
    return render(request, "reviews/makeselect.html", context)

关于python - 如何通过多种形式过滤模型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45143291/

10-08 22:24
查看更多