2017-07-17 83 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)