Calculate Input Fields while user is filling data in form – Django Model Form

Question:

I have a user form through which I can save data to the database.

I want certain fields to be auto calculated while I am filling the the form.

For e.g. Net Weight = Gross Weight – Tier Weight and stuff like that.

I also want to add RADIO BUTTONS for fields like LOADING, UNLOADING, DEDUCTION, etc. where values will be calculated when user selects one of the option given.

Design of the type of form I want, I just don’t know how to make that using Django:

enter image description here

I am using Django Model Form.

Models.py

class PaddyPurchase(models.Model):
    ref_no = models.IntegerField(primary_key='true')
    token_no = models.CharField(max_length=20, unique='true')
    agent_name = models.CharField(max_length=20)
    trip_no = models.IntegerField()
    date = models.DateField()
    vehicle_no = models.CharField(max_length=10)
    bora = models.IntegerField()
    katta = models.IntegerField()
    plastic = models.IntegerField()
    farmer_name = models.CharField(max_length=30)
    farmer_address = models.CharField(max_length=40)
    farm_mob = models.CharField(max_length=10)
    gross_weight = models.IntegerField()
    tier_weight = models.IntegerField()
    net_weight = models.IntegerField()
    bora_weight = models.IntegerField()
    suddh_weight = models.FloatField()
    loading = models.IntegerField()
    unloading = models.IntegerField()
    unloading_point = models.CharField(max_length=20)
    dharamkanta_man = models.CharField(max_length=10)
    rate = models.IntegerField()
    bardana = models.CharField(max_length=7)
    gross_total = models.IntegerField()
    deduction = models.IntegerField()
    kanta = models.IntegerField()
    hemali = models.IntegerField()
    our_vehicle_rent = models.IntegerField()
    agent_commission = models.IntegerField()
    other_amt = models.IntegerField()
    other_remarks = models.CharField(max_length=50)
    advance = models.IntegerField()
    net_total = models.IntegerField()


 # For returning data in ADMIN SITE
 def __str__(self):
     return 'PaddyPurchase'

Forms.py

class PaddyPurchaseForm(forms.ModelForm):
# Code for changing DATE FORMAT (from YYYY-MM-DD to DD-MM-YYYY)
date = forms.DateField(
    widget=forms.DateInput(format='%d%m%Y'),
    input_formats=['%d-%m-%Y']
)

class Meta:
    model = PaddyPurchase
    fields = ['ref_no',
              'token_no',
              'agent_name',
              'trip_no',
              'date',
              'vehicle_no',
              'bora',
              'katta',
              'plastic',
              'farmer_name',
              'farmer_address',
              'farm_mob',
              'gross_weight',
              'tier_weight',
              'net_weight',
              'bora_weight',
              'suddh_weight',
              'loading',
              'unloading',
              'unloading_point',
              'dharamkanta_man',
              'rate',
              'bardana',
              'gross_total',
              'deduction',
              'kanta',
              'hemali',
              'our_vehicle_rent',
              'agent_commission',
              'other_amt',
              'other_remarks',
              'advance',
              'net_total'
              ]

Viwes.py

def add_record(request):

if request.method == "POST":
    form = PaddyPurchaseForm(request.POST)
    if form.is_valid():
        form.save(commit=True)
        messages.success(request, "Data Saved Successfully. - Lucky")
        return index(request)
    else:
        messages.error(request, "Error!!!")
return redirect("index")
Asked By: Lucky

||

Answers:

This is a problem to be solved with JavaScript. Django can handle the server-side, but since you want these calculations to be done as the user types, or enters information before it is submitted, you need JavaScript to handle the client-side. Once the form is filled in, you can still send it to the server (the views) using what you already have with Django.

So how do you do this with JavaScript? First give each of the inputs an id, so you can access them in your JavaScript (JS) script, for example,

<input id='gross_weight' ...>
<input id='tier_weight' ...>
<input id='net_weight' ...>

Next, use JS input event or a change event to detect when the user has inputted a value, do your calculations, and then update the values in your form:

<script>
    // Get the input elements by targeting their id:
    const gross_input = document.getElementById('gross_weight');
    const tier_input = document.getElementById('tier_weight');
    const net_input = document.getElementById('net_weight');
 
    // Create variables for what the user inputs, and the output:
    let gross = 0;
    let tier = 0;
    let net = 0;

    // Add an event listener to 'listen' to what the user types into the inputs:
    gross_input.addEventListener('input', e => {
      gross = e.target.value;
      updateNet()
    });
    tier_input.addEventListener('input', e => {
      tier = e.target.value;
      updateNet()
    });

    // Update the value of net based on what the user inputs in for gross and tier
    function updateNet(e) {
        net = gross - tier;
        net_input.value = net;
    }
</script>

When the user submits the form, Django takes over.

Answered By: raphael

There is an django app that facilitates the calculation in the frontend by writing the expression in the definition of the form widget.

django-calculation you can get it with:

pip install django-calculation

An example of how you could achieve the calculation simply by defining an expression in a ModelForm.

from django import forms

# import your PaddyPurchase model
from .models import PaddyPurchase

# import the calculation module from django-calculation app
import calculation


class PaddyPurchaseForm(forms.ModelForm):
    # Code for changing DATE FORMAT (from YYYY-MM-DD to DD-MM-YYYY)
    date = forms.DateField(
        widget=forms.DateInput(format="%d%m%Y"), input_formats=["%d-%m-%Y"]
    )

    class Meta:
        model = PaddyPurchase
        fields = [
            "ref_no",
            "token_no",
            "agent_name",
            "trip_no",
            "date",
            "vehicle_no",
            "bora",
            "katta",
            "plastic",
            "farmer_name",
            "farmer_address",
            "farm_mob",
            "gross_weight",
            "tier_weight",
            "net_weight",
            "bora_weight",
            "suddh_weight",
            "loading",
            "unloading",
            "unloading_point",
            "dharamkanta_man",
            "rate",
            "bardana",
            "gross_total",
            "deduction",
            "kanta",
            "hemali",
            "our_vehicle_rent",
            "agent_commission",
            "other_amt",
            "other_remarks",
            "advance",
            "net_total",
        ]
        # define a custom widget to your net_weight field
        widgets = {
            'net_weight': calculation.FormulaInput('gross_weight-tier_weight')
        }
        

be sure to include {{ form.media }} in your template.

Answered By: Blasito