首页 文章

如何过滤django modelformset manytomany memeber的查询集

提问于
浏览
1

我可以't use the proper code but I found the pizza/toppings question and it'关闭所以我正在修改它来问我的问题 . Django ModelForm for Many-to-Many fields

我们有Pizza和Topping很棒 . 让我们说我们经营一系列商店,并非所有商店都有所有成分 . 这意味着我们需要一个Store类,它具有一个位置,并且有许多用于浇头 . 然后让我们推出一个引用商店的订单,并且因为您经常订购不止一个,所以在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,但我遇到了困难 .

基本上我可以告诉我,我需要以某种方式将信息从视图传播到formset到表单,以便可以正确初始化表单上的查询集 . 我只是无法弄清楚如何做到这一点 .

所以这是我最接近的似乎是如何确保如此工作:Django filter ModelFormSet field choices... different from limiting the Formset's queryset

回应那些想要发布一个非工作示例的人

关键是我不是要求某人发布完全解决我的问题的确切的10行代码,而是我正在展示我的知识缺乏的地方 . 我知道我生成了一个PizzaFormSet,并最终在该代码的内部某处使用我指定的PizzaForm . 但我不知道如何成功地将信息从PizzaFormSet传递到PizzaForm .

基本上我愿意放弃赏金,以获得关于这个难题的哪些部分我缺失的建议 .

问题出在哪里

我在forms.py(PizzaForm)中定义了一个表单,它需要为Topping获取一个依赖于情境的查询集 . 视图order_pizzas决定了哪个餐厅将制作和提供比萨饼,并且该餐厅提供的配料可能与其他餐厅不同 .

我不知道如何将视图中的信息传播到表单,通常你只是将表单子类化并添加一些额外的init kwargs来做任何你想做的事情 .

但在这种情况下,我使用的是formset而不是单一的形式 . 这意味着我必须找到(或制作)一些 Channels 将餐馆信息和/或特定查询集从视图传递到表单到表单 . 我认为这是我的主要困惑和/或无知 .

2 回答

  • 3

    这是一个解决方案 . 可能有一个更好的,但这应该工作 . 循环遍历formset中的所有表单,并更改 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__ ,然后在那里更改顶部的选择 . 但我认为上述解决方案是最快捷,最简单的 . 它只是引入了一个额外的循环 .

  • 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 (即使用管理员,shell脚本或API调用),你仍然可以得到无法填充的订单 .

相关问题