11

Im trying to create a dynamic form that uses a models relationship to generate the formset.

Here is a brief overview of the application. I have a customer table (joined to django admin user table), products table, order table and some join tables. The customer_product table contains a pre built order form that can be edited. I use some join table to create new order_instances that can be referenced from the order table for historical data.

` Customer has one to one relationship with user table

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


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

` Customer has and belongs to many products

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

' Customer has and belongs to many products. Customer has many orders

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

I don't know how to use formsets in this case, that will let be build dynamic form and save to a customer_product_order table and order table. Currently i have the form outputting but it's checking the customer_product table the second time rather than letting the forms.py oncstruct it. Also couldnt construct the html array in forms.py page.

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)

template

{% 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 width="10%">Quantity</th>
                    <th width="20%">Item</th>
                    <th width="70%">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 %}

UPDATE

With regards to comments about models. I have detailed the relationships above as best as I can. The design and requirements of the app are as follow. Each customer hasone user. A customer order sheet is prebuilt by administrators and store in the customer_product table. Customer hasand belongstomany products and customer hasmanyorders. When an order is placed by the customer, a new order record is added, and the customer_products_order join table is populated, along with quantities of each product.

The customer_product table is pre-populated by administrators. The customer_product_order (join) and order table is populated by customers.

I was using the following join to grab customer information from the order model. I couldn't find any other way to recursively join the customer table from the order model. I may be wrong. Even though this is beyond this question, I really appreciate any comments on my code!

models.ManyToManyField('CustomerProduct', through='CustomerProductOrder')
4
  • Before going into the details regarding dynamic formsets generation, I am a bit curious about your model classes. Could you please give more details regarding the intention behind each Model ? In particular, your design makes it seem you want to be able to have different customers for a single order, is that intentional ? Commented Aug 17, 2015 at 10:01
  • No, that isn't intentional. My intention is not to have different customer for a single order. Company = customer. When the order is placed, the field for "person placing order" is the employee placing the order on the day. Commented Aug 17, 2015 at 13:45
  • In your design, Order has many CustomerProducts. Since each CustomerProduct has a Customer, it results that a single Order can have several different Customers. Also, because the ManyToMany relation is bidirectional, the same CustomerProduct can be part of different Orders. All those choices are going against the intuitive design (example, violating the fact that there is a single Customer for any given Order). I think you should give more details about the intention behind each of your Model classes, and your design decisions, in order to receive some answers. Commented Aug 17, 2015 at 13:59
  • Hi @AdN i have updated the question with relationships and summary of app design and requirements. Commented Aug 17, 2015 at 15:19

1 Answer 1

2
+75

From the discussion we started in the comments and your updated answer, I am unsure about the purpose of you customer_product table ? I will update my answer if I finally get it.

(It would actually seem to me that your customer_id field in customer_product model is redundant with the customer_id field in customer_product_order, making the table customer_product not actually usefull.)


To model a product ordering system, you could perhaps move the customer_id at the order level (from what I understand of your requirements, there a Customer has many orders, but and order has a single customer, which the current design fails to implement), giving you:

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

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

If this model could suit your need, can you clarify what is the question you are facing ?


EDIT: I think the data modeling is slightly off, and it is not conveying the right message about what you are trying to achieve (making it complicated to help ;). In particular:

Customer hasand belongstomany products

Seems it could be a misconception: why would a Customer belong to a product ?
It seems more natural that the Customer would have a many-to-one relationship with Order instances. And a Order would have a many-to-one relationship with Products, potentially joined through an external table containing the quantity field (i.e., your CustomerProductOrder table).

That would give you this updated and simplified model:



    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


Could you please explain why this more trivial design would not be fit for your purpose ? (Hoping that it will allow us to better understand your requirements)

Sign up to request clarification or add additional context in comments.

6 Comments

The customer_product table is pre-populated by administrators. The customer_product_order (join) and order table is populated by customers.
@madphp And what is the purpose of this administrators populated table ? Is it just an alternative form of order: either the customer creates the order himself, either the administrators do ?
Another scenario would be. I made an order with one sheet of products. The admin comes in at a later date and removes a product from customer_product table, but that old product is still referenced in the customer_product_order table. Its main purpose is for historical data.
the customer_product table is a join table for an administrator to construct a order sheet or invoice.
@madphp I updated the answer with a proposal for a simplified yet complete modelling of a trivial ordering system. If it does not work for the application you are currently writing, could you please explain why ? My hope is that if you state the defects of this model for your problem, it will make your requirements more explicit : )
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.