2014-03-13 158 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调用),您仍然可能以无法完成的订单结束。

相关问题