Django(模型)表单字段:Manytomany具有键值对

时间:2014-07-27 01:54:13

标签: django django-models django-forms

我有一种情况,我需要做一些类似于在formset中呈现formset的事情。但在转向解决方案之前,我更关注问题。

首先是英语:

  • 我正在从仓库创建货件。
  • 每件货件可以包含多行(product_type和package_type的唯一组合)和item_count
  • 然而,对于每一行,可能有多个"包" - 具有item_count的product_type的package_type。可以将其视为一批。
  • 客户只对每个product_type / package_type
  • 看一行感兴趣
  • 但我们需要提取库存并正确归因每批的特定单位,以便进行库存控制,召回控制等功能。因此,派遣人员对准确发运的包裹感兴趣。
  • 此外,销售人员输入仅指定product_type / package_type的SalesOrder。他们对包裹也不感兴趣。 (想想下个月的预定订单 - 谁知道库存会是什么?)。

现在的模型(为简洁起见而简化):

class Package(models.Model):
    create_date = models.DateField()
    quantity = models.FloatField()
    package_type = models.ForeignKey(PackageType, on_delete=models.PROTECT)
    product_type = models.ForeignKey(ProductType, on_delete=models.PROTECT)

class CheckOut(models.Model):
    package = models.ForeignKey(Package, on_delete=models.PROTECT)
    create_date = models.DateField()
    quantity = models.FloatField()

class Shipment(models.Model):
    sales_order = models.ForeignKey(SalesOrder, null=True, blank=True)
    ship_date = models.DateField(default=date.today,
        verbose_name='Ship Date') 

class ShipmentLine(models.Model):
    shipment = models.ForeignKey(Shipment, null=True, blank=True)
    sales_order_line = models.ForeignKey(SalesOrderLine, null=True, blank=True)
    quantity = models.FloatField(verbose_name='Quantity Shipped')
    checkout = models.ManytoManyField(CheckOut)

我目前在CheckOut:ShipmentLine的1:M关系约束下运行良好。然而,当将其改为M:M时,事情会变得非常明显。 在1:M版本中,Shipment表单(加上ShipmentLines的formset)如下所示:

class CreateShipmentForm(forms.ModelForm):
    class Meta:
        model = om.Shipment

    contact = forms.ModelChoiceField(
        queryset=om.Contact.objects.filter(is_customer=True, active=True),
        label='Customer')
    customer_ref = forms.CharField(required=False, label='Customer Reference')
    sales_order = forms.ModelChoiceField(queryset=om.SalesOrder.objects.all(),
        required=False, widget=forms.HiddenInput())
    number = forms.CharField(label='Shipment Number', required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'}))

class CreateShipmentLineForm(forms.ModelForm):
    class Meta:
        model = om.ShipmentLine
        widgets = {
            'checkout': forms.HiddenInput()
        }
    fields = ('package', 'quantity', 'id',
        'sales_order_line', 'checkout')

    id = forms.IntegerField(widget=forms.HiddenInput())
    sales_order_line = forms.ModelChoiceField(
        widget=forms.HiddenInput(), required=False,
        queryset=om.SalesOrderLine.objects.all())
    package = forms.ModelChoiceField(required=True, queryset=None)  # queryset populated in __init__, removed for brevity

因此对于1:M,我可以选择一个包,设置数量并完成。 对于M:M,我需要选择product_type,package_type,然后选择一个或多个包,并为每个包选择一个数量。 (我将在表单中使用JS来过滤这些)

在我的脑海中,我有几种可能性:

  • 为包和数量创建(子)formset并包含在(父)formset的每一行中
  • 创建某种多字段,多值矩阵自定义表单字段并使用
  • 构建一个模态对话框,其中M:M的内容发生,并以某种方式将结果保存到验证,保存的形式。

我希望我已经正确而清楚地解释了它。它是我遇到的Django表单中最复杂的应用程序,我不确定每个选项的限制/优缺点是什么。

有没有人遇到过这种情况并有解决方案?或者对明智的任何话语?

我提前感谢,

1 个答案:

答案 0 :(得分:0)

我有类似的情况,我正在做类似你的第二和第三选择: 我已经覆盖了__init__(),并且在调用super之后,我有一个循环为每个字段添加一个值选择器(当然你可以在这里使用一个自定义元素) 然后覆盖save()并在调用super后,我处理添加所有值的额外字段。