【问题标题】:Django (Model)Form Field: Manytomany with key value pairDjango (Model)Form Field: Manytomany with key value pair
【发布时间】:2014-07-27 01:54:13
【问题描述】:

我有一种情况,我需要做一些类似于在表单集中呈现表单集的事情。但我宁愿先关注问题,然后再寻求解决方案。

先用英文:

  • 我正在从仓库创建货件。
  • 每个货件可以包含多行(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 的表单集)如下所示:

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,然后选择 1 个或多个包,并为每个包选择一个数量。 (我将在表单中使用 JS 来过滤这些)

在我看来,我有几个可能性:

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

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

有没有人遇到过这种情况并有解决办法?或者对智者说什么?

提前致谢,

内森

【问题讨论】:

    标签: django django-models django-forms


    【解决方案1】:

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

    【讨论】:

    • 我正在考虑选择第​​二个选项。使用 Select 和 NumberInput 创建自定义 MultiWidget。然后根据需要重复(还没有找到最好的方法)。并在前端使用JS进行增删。
    猜你喜欢
    • 2012-01-08
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 2022-12-28
    • 2016-05-10
    • 2016-01-02
    相关资源
    最近更新 更多