2017-07-17 82 views
1

我有我想通过相互依存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> 

现在,我必须要通过“做”的第一种形式的说法贴的时候,第二种观点,然后用它通过与制造汽车的实例进行筛选。但是,我通过的是“无”,并获得选择一个有效的选择。该选择不是可用选择之一。第二种形式的错误。

任何建议或反馈将受到欢迎,并非常感谢。

谢谢。

+0

您需要通过第二个视图将您从第一个表单获得的信息传递给第二个表单。我认为你需要重写第二种形式的__init__来调整所需字段的查询集。以下是我当天做的 def __init __(self,* args,** kwargs): self.request = kwargs.pop('request',None) super(GameForm,self).__ init __( * args,** kwargs) if not self.request.user.is_staff: self.fields ['publisher']。queryset = Publisher.objects.filter(id = self.request.user.id) ' –

回答

1

第一点:模型表单用于创建/编辑模型,所以您应该在这里使用普通表格。您的错误来自您的ModelSelectForm中的make字段,但不会在任何地方设置其值。此外,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> 

关于“通过”使第二个视图“有问题”:你的代码中没有任何内容snipp您可以将用户定向到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) 
+0

Thank你为你详细的答案。我做了更改,然后编辑了我的** MakeSelectForm **和** make_select_view ** [据此](http://oi67.tinypic.com/23kzxq0.jpg)。但是,我仍然无法将所选的“make”传递给第二个视图,例如其URL:_/None /?submitted = 1&make = BMW_如果手动更改“None”,则可以进行过滤。 – steerr

+0

您没有指定从第一个视图到第二个视图的方式,而且在您的代码片段中找不到它。但我在答案中增加了一个典型的例子,在成功提交时从第一个视图重定向到第二个视图。 –

+0

再次感谢。我认为重定向是通过'form action =“{%url'reviews:model-select'make%}”'在模板中完成的。无论如何,[我编辑我的代码](http://oi66.tinypic.com/240yw3p.jpg),但仍然得到“无”,而不是选定的制造。 – steerr

1

由于我在评论中发布的代码片段的格式变得混乱起来,所以我在这里写下这个答案。

def __init__(self, *args, **kwargs): 
    self.request = kwargs.pop('request', None) 
    super(GameForm, self).__init__(*args, **kwargs) 
    if not self.request.user.is_staff: 
     self.fields['publisher'].queryset = Publisher.objects.filter(id=self.request.user.id)