2014-03-13 75 views
1

我不能使用正確的代碼,但我發現比薩餅/澆頭的問題,它很接近,所以我修改它問我的問題。 Django ModelForm for Many-to-Many fields如何篩選的查詢集Django的modelformset多對多memeber

我們有Pizza和Topping,它們都很棒。假設我們經營一系列連鎖店,並非所有店鋪都擁有所有配料。這意味着我們需要一個Store類,它有一個位置和一個很多tomay的配料。然後讓我們推出一個參考商店的訂單,並且在Pizza上有很多東西,因爲您經常訂購多個商品。

models.py

from django import models 

class Topping(models.Model): 
    name = models.TextField() 

class Pizza(models.Model): 
    size = models.TextField() 
    toppings = models.ManyToManyField(Topping) 

class Restaraunt(models.Model): 
    name = models.TextField() 
    toppings = models.ManyToManyField(Topping) 


class Order(models.Model): 
    customer = models.ForeignKey('User') 
    location = models.ForeignKey(Restaraunt) 
    pizzas = models.ManyToManyField(Pizza) 

forms.py

from django import forms 
from django.forms import ModelForm 
from models import * 

class PizzaForm(ModelForm): 

    class Meta: 
     model = Pizza 

    toppings = forms.ModelMultipleChoiceField(
     widget=forms.CheckboxSelectMultiple(), 
     queryset=Topping.objects.all() 
    ) 

views.py

from django.shortcuts import render, redirect, get_object_or_404 
from django.forms.models import modelformset_factory 
from django.forms import CheckboxSelectMultiple 

from models import * 
from forms import * 


def order_pizzas(request, order_id): 
    order_id = int(order_id) 
    order = get_object_or_404(Order, id=order_id) 

    restaraunt = order.restaraunt 

    PizzaFormSet = modelformset_factory(Pizza, form=PizzaForm, extra=1) 

    pizza_form = PizzaFormSet(request.POST or None) 

    return render(request, "place_order.html", { 
     'restaraunt': restaraunt, 
     'pizza_form': pizza_form, 
    }) 

請不要打我了,如果那些不實際運行太多。就像我說過的,由於種種原因,我不能在這裏發佈真正的代碼,部分原因是因爲它很龐大。

爲了這個例子的緣故,假設這個人已經找到了離他們家最近的餐廳並且開始了訂購過程。

我已經試過在小部件傳遞給modelformset_factory適當的名稱和選項,但沒有傳播。

widgets = {'toppings': 
    CheckboxSelectMultiple(
     choices=[t.id for t in restaraunt.toppings.all().order_by('-id')] 
    )} 

我也試圖擴大BaseModelFormSet到額外的數據傳遞和嘗試,並獲取進入PizzaForm但我卡住了。

基本上我可以告訴大家,我需要以某種方式傳播從視圖信息的表單集的形式,使窗體上的查詢集可以正確初始化。我無法弄清楚如何做到這一點。

所以這是我找到的答案最接近的,但我似乎無法弄清楚如何使確保工作: Django filter ModelFormSet field choices... different from limiting the Formset's queryset

針對誰是要糾纏我的人發佈非工作示例

的一點是,我不想問的人發佈的確切10行的代碼,將徹底解決我的問題,而是我展示在我的知識不足。我知道我生成了一個PizzaFormSet,並最終在它使用我指定的PizzaForm的代碼中找到了它。但我不知道如何成功地將信息從PizzaFormSet傳遞給PizzaForm。

基本上我願意放棄一個關於我失蹤這個難題的部分建議的獎勵。

問題出在哪裏

我已經定義在forms.py(PizzaForm)一種形式,需要得到該層貼situationally相關的查詢集。視圖order_pizzas決定哪家餐廳製作並提供比薩餅,該餐廳可用的配料可能與其他餐廳不同。

我不知道如何將這些信息從視圖傳播到窗體,通常你只是子類化窗體並添加一些額外的init kwargs來做任何你想做的事情。

但在這種情況下,我使用的是formset而不是單一的形式。這意味着我必須查找(或製作)某個頻道,將餐廳信息和/或特定查詢集從視圖傳遞到表單集。我認爲這是我的困惑和/或無知的主要觀點。

+1

*請不要打我......發佈實際的代碼......巨大的*實際上發佈大量代碼將是一個同樣有效的理由,因爲發佈的示例不會運行。它只是違反了[sscce](http://www.sscce.org/)的不同部分... –

+0

你錯過了我的問題Chris的觀點。 –

+0

試試這個:給表單字段添加'restaraunt.toppings.all()。order_by(' - id')',並且不要給複選框小部件提供任何選擇。我沒有作爲答案張貼,因爲我沒有測試它,但我敢肯定它是有效的 – yuvi

回答

3

這是一個解決方案。可能會有更好的一個,但這應該起作用。遍歷表單集中的所有表單,並在toppings字段中更改choices變量。就像這樣:

pizza_form = PizzaFormSet(request.POST or None) 

choices = [(t.pk, unicode(t)) for t in restaraunt.toppings.all().order_by('-id')] 

for form in pizza_form: 
    form.fields['toppings'].choices = choices 

您也可以覆蓋BaseModelFormset並覆蓋_contruct_forms方法,傳遞restaraunt對象到窗體的__init__,然後更改餡料的選擇那裏。但我認爲上述解決方案是最快最簡單的。它只是引入了一個額外的循環。

+2

請使用forloop生成循環中的選項,此處不需要嵌套循環。 '選擇= [']'循環外和'form.fields ['toppings']。choices = choices'在循環中。 – davur

+0

好點。我編輯了答案。 – jproffitt

+0

終於有了一個有用的答案! – JasonTS

1

你可以有一個工廠,使PizzaForms:

def pizzaform_factory(restaurant): 
    class PizzaForm(ModelForm): 

     class Meta: 
      model = Pizza 

     toppings = forms.ModelMultipleChoiceField(
      widget=forms.CheckboxSelectMultiple(), 
      queryset=restaurant.toppings.all() 
     ) 
    return PizzaForm 

並在您的視圖中使用它:

PizzaForm = pizzaform_factory(restaurant) 
PizzaFormSet = modelformset_factory(Pizza, form=PizzaForm, extra=1) 

也許您的模型的約束,以確保您不能創建不可能訂單會好的。如果您沒有使用pizzaform_factory(即使用admin,shell腳本或API調用),您仍然可能以無法完成的訂單結束。

相關問題