Django 动态表单,带有 HTML 数组的表单集

Posted

技术标签:

【中文标题】Django 动态表单,带有 HTML 数组的表单集【英文标题】:Django dynamic form, formsets with HTML array 【发布时间】:2015-11-08 04:06:46 【问题描述】:

我正在尝试创建一个使用模型关系生成表单集的动态表单。

这里是应用程序的简要概述。我有一个客户表(加入到 django 管理员用户表)、产品表、订单表和一些连接表。 customer_product 表包含一个可编辑的预构建订单表单。我使用一些连接表来创建新的 order_instances,可以从 order 表中引用历史数据。

`客户与用户表是一对一的关系

customer table
--------------
id


product table
-------------
id | product_id

`客户拥有并属于许多产品

customer_product (pre-built order templates)
----------------
id | customer_id | product_id

' 客户拥有并属于许多产品。客户有很多订单

customer_product_order (customer initiated order)
----------------------
id | customer_id | product_id | order_id | quantity

order (main order table. each record contains meta data for that order)
-------
id | invoice_number | delivery_date

我不知道在这种情况下如何使用表单集,这将让我们构建动态表单并保存到 customer_product_order 表和 order 表。目前我有表单输出,但它第二次检查 customer_product 表,而不是让 forms.py oncstruct 它。也无法在forms.py页面中构造html数组。

models.py

from django.conf import settings
from django.db import models
from datetime import datetime
import pprint

class Customer(models.Model):
    customer = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to='groups__name': "customers")
    customer_product = models.ManyToManyField('Product', through='CustomerProduct')
    company_name = models.CharField(max_length=255)
    address1 = models.CharField(max_length=255)
    address2 = models.CharField(max_length=255)
    city = models.CharField(max_length=255)
    state = models.CharField(max_length=255)
    zip_code = models.CharField(max_length=255)
    created_date = models.DateTimeField('date created')
    def __unicode__(self):
        return self.company_name

class CustomerProduct(models.Model):
    customer = models.ForeignKey('Customer')
    product = models.ForeignKey('Product')
    def __unicode__(self):
        return self.customer.company_name

class Product(models.Model):
    item = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    def __unicode__(self):
        return self.description

class Order(models.Model):
    customer_product_order = models.ManyToManyField('CustomerProduct', through='CustomerProductOrder')
    purchase_order_number = models.CharField(max_length=10)
    person_placing_order = models.CharField(max_length=255)

class CustomerProductOrder(models.Model):
    order = models.ForeignKey('Order')
    customer_product = models.ForeignKey('CustomerProduct')
    quantity = models.IntegerField(default=0)
    instructions = models.CharField(max_length=2000)
    order_correct = models.BooleanField()
    def __unicode__(self):
        return self.customer_product.customer.company_name

    class Meta:
        verbose_name = "Customer Order"

forms.py

from django import forms

from .models import CustomerProduct

class OrderForm(forms.Form):
    def __init__(self, *args, **kwargs):
        products = CustomerProduct.objects.filter(customer_id=1)

        super(OrderForm, self).__init__(*args, **kwargs)
        counter = 1
        for q in products:
            self.fields['product[quantity][' + str(q.id) + ']' + str(counter)] = forms.CharField(required=False)
            self.fields['product[item][' + str(q.id) + ']' + str(counter)] = forms.CharField(required=False)
            self.fields['product[description][' + str(q.id) + ']' + str(counter)] = forms.CharField(required=False)
            counter += 1

    purchase_order_number = forms.CharField(required=True)
    person_placing_order =  forms.CharField(required=True)
    delivery_date_request = forms.DateField(required=True,widget=forms.DateInput(attrs='class':'datepicker'))
    instructions = forms.CharField(required=False,widget=forms.Textarea(attrs='rows': 5, 'cols': 100, 'class': 'form-control'))
    confirm_order = forms.BooleanField(required=True)

views.py

from django import forms

from .models import CustomerProduct

class OrderForm(forms.Form):
    def __init__(self, *args, **kwargs):
        products = CustomerProduct.objects.filter(customer_id=1)

        super(OrderForm, self).__init__(*args, **kwargs)
        counter = 1
        for q in products:
            self.fields['product[quantity][' + str(q.id) + ']' + str(counter)] = forms.CharField(required=False)
            self.fields['product[item][' + str(q.id) + ']' + str(counter)] = forms.CharField(required=False)
            self.fields['product[description][' + str(q.id) + ']' + str(counter)] = forms.CharField(required=False)
            counter += 1

    purchase_order_number = forms.CharField(required=True)
    person_placing_order =  forms.CharField(required=True)
    delivery_date_request = forms.DateField(required=True,widget=forms.DateInput(attrs='class':'datepicker'))
    instructions = forms.CharField(required=False,widget=forms.Textarea(attrs='rows': 5, 'cols': 100, 'class': 'form-control'))
    confirm_order = forms.BooleanField(required=True)

模板

% extends "base.html" %

% block orderform %
    % if form.errors %
        <p style="color: red;">
            Please correct the error form.errors|pluralize  below.
        </p>
    % endif %

    <form action="/onlineordering/" method="POST">

        <form class="form-inline">

            % csrf_token %

            <div class="row">
                <div class="col-md-6">

                    <div class="form-group">
                        <div class="row">
                            <div class="col-md-5"><label for="exampleInputName2">Date</label></div>
                            <div class="col-md-7"> datenow </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="row">
                            <div class="col-md-5"><label for="exampleInputName2">Customer ID:</label></div>
                            <div class="col-md-7"> username </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="row">
                            <div class="col-md-5"><label for="exampleInputName2">Address</label></div>
                            <div class="col-md-7">
                                1 Main Street<br />
                                Town<br />
                                State<br />
                            </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="row">
                            <div class="col-md-5"><label for="exampleInputName2">Purchase Order Number</label></div>
                            <div class="col-md-7"> form.purchase_order_number </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="row">
                            <div class="col-md-5"><label for="exampleInputEmail2">Person Placing Order</label></div>
                            <div class="col-md-7"> form.person_placing_order </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="form-group">
                            <div class="row">
                                <div class="col-md-5"><label for="exampleInputEmail2">Requested Delivery Date</label></div>
                                <div class="col-md-7"> form.delivery_date_request </div>
                            </div>
                        </div>
                    </div>

                </div>
                <div class="col-md-6">
                    <p class="text-right">

                    </p>
                </div>
            </div>

            <table class="table table-bordered online-ordering-table">
                <tr>
                    <th >Quantity</th>
                    <th >Item</th>
                    <th >Description</th>
                </tr>

                % for product in products %

                <tr>
                    <td><input name="product_quantity"  /></td>
                    <td> product.product.item </td>
                    <td> product.product.description </td>
                </tr>

                % endfor %

            </table>

            <div class="form-group">
                <label for="exampleInputEmail2">Special Instructions / Comments</label>
                 form.instructions 
            </div>

            <div class="form-group">
                <div class="checkbox">
                    <label>
                         form.confirm_order  I concede the order above is correct and authorize Company to fulfill this order
                    </label>
                </div>
            </div>

            <input class="btn" type="submit" value="Submit">
        </form>

    </form>
% endblock %

更新

关于模型的 cmets。我已尽我所能详细说明上述关系。该应用程序的设计和要求如下。每个客户hasone 用户。客户订单表由管理员预先构建并存储在 customer_product 表中。客户hasand belongstomany 产品和客户hasmanyorders。当客户下订单时,会添加一条新订单记录,并填充 customer_products_order 连接表以及每种产品的数量。

customer_product 表由管理员预先填充。 customer_product_order (join) 和 order 表由客户填充。

我正在使用以下联接从订单模型中获取客户信息。我找不到任何其他方式从订单模型递归地加入客户表。我可能错了。尽管这超出了这个问题,但我非常感谢我的代码中的任何 cmets!

models.ManyToManyField('CustomerProduct', through='CustomerProductOrder')

【问题讨论】:

在详细了解动态表单集生成之前,我对您的模型类有点好奇。您能否详细说明每个 Model 背后的意图?特别是,您的设计让您看起来希望能够为 单个订单拥有 不同的客户,这是故意的吗? 不,这不是故意的。我的目的是不要让一个订单有不同的客户。公司=客户。下单时,“下单人员”字段为当天下单的员工。 在您的设计中,Order许多 CustomerProducts。由于每个CustomerProduct 都有一个Customer,因此单个Order 可以有几个不同的Customers。此外,由于多对多关系是双向的,相同的CustomerProduct 可以是不同Orders 的一部分。所有这些选择都违背了直观的设计(例如,违反了任何给定的Order 都有一个Customer 的事实)。我认为您应该详细说明每个 Model 类背后的意图以及您的设计决策,以便获得一些答案。 嗨@AdN,我已经更新了问题,其中包含应用程序设计和要求的关系和摘要。 【参考方案1】:

根据我们在 cmets 中开始的讨论和您更新的答案,我不确定您 customer_product table 的目的?如果我终于得到它,我会更新我的答案。

(实际上在我看来,customer_product 模型中的 customer_id 字段与 customer_product_order 中的 customer_id 字段是多余的,使得表 customer_product 实际上没有用。)


要为产品订购系统建模,您也许可以将customer_id 移动到order 级别(据我了解您的要求,Customer 有很多订单,但是订单有 单个客户,当前设计未能实现),为您提供:

product_order
----------------------
id | product_id(ForeignKey) | order_id(ForeignKey) | quantity

order
-------
id | customer_id(ForeignKey) | invoice_number | delivery_date

如果这个模型可以满足你的需要,你能澄清一下你面临的问题是什么吗?


编辑:我认为数据建模略有偏差,并且它没有传达有关您要实现的目标的正确信息(使帮助变得复杂;)。特别是:

客户拥有并属于多个产品

这似乎是一种误解:为什么客户会属于产品?CustomerOrder 实例具有多对one 关系似乎更自然。而Order 将与Products 具有多对one 关系,可能通过包含quantity 字段的外部表(即您的@ 987654336@表)。

这会给你这个更新和简化的模型:



    customer table
    --------------
    id | ...


    product table
    -------------
    id | description | ...


    order
    -------
    id | customer_id(ForeignKey) | person_placing_order | invoice_number | delivery_date


    order_content (~= customer_product_order)
    ----------------------
    id | order_id(ForeignKey)  | customer_id | product_id(ForeignKey) | product_quantity


您能否解释一下为什么这种更琐碎的设计不适合您的目的? (希望能让我们更好地了解您的需求)

【讨论】:

customer_product 表由管理员预先填充。 customer_product_order (join) 和 order 表由客户填充。 @madphp 这个管理员填充表的目的是什么?它只是一种替代形式的订单:要么客户自己创建订单,要么管理员创建? 另一种情况是。我用一张产品下了订单。管理员稍后进来并从 customer_product 表中删除了一个产品,但该旧产品仍然在 customer_product_order 表中引用。它的主要用途是历史数据。 customer_product 表是一个连接表,供管理员构建订单表或发票。 @madphp 我更新了答案,提出了一个简单但完整的简单订购系统建模的建议。如果它不适用于您当前正在编写的应用程序,您能否解释一下原因?我的希望是,如果您针对您的问题说明此模型的缺陷,它将使您的要求更加明确:)

以上是关于Django 动态表单,带有 HTML 数组的表单集的主要内容,如果未能解决你的问题,请参考以下文章

带有 HTML 表单的 Django

如何使用带有 html 的 Django 表单制作提交按钮

带有内联表单集的 Django 表单验证

带有验证和多个表单处理的 Django Ajax 提交

Django : HTML 表单操作指向带有 2 个参数的视图(或 url?)

Django从html页面访问动态表单值到视图[关闭]