--PROBLEM--
I have created a basic calculator using Django. The app takes some basic form inputs before executing some calculations and returning the outcomes to the user, however I want the user's inputs to remain visible in the form on submission. At present the followin experience occurs.
- User enters values into form and submits using 'Calculate' button.
- Results are returned as expected but form and values are no longer present.
- User can press 'Calculate' button to return to start of process and blank form.
--DESIRED OUTCOME--
--CODE--
forms.py
from django import forms
class InvestmentForm(forms.Form):
starting_amount = forms.FloatField()
number_of_years = forms.FloatField()
return_rate = forms.FloatField()
annual_additional_contribution = forms.FloatField()
views.py
from django.shortcuts import render
from django.views import View
from .forms import InvestmentForm
class Index(View):
def get(self, request):
form = InvestmentForm()
return render(request, 'loancalculator/index.html', {'form': form})
def post(self, request):
form = InvestmentForm(request.POST)
if form.is_valid():
total_result = form.cleaned_data['starting_amount']
total_interest = 0
yearly_results = {}
for i in range(1, int(form.cleaned_data['number_of_years'] 1)):
yearly_results[i] = {}
# CALCULATE THE INTEREST
interest = total_result * (form.cleaned_data['return_rate'] / 100)
total_result = interest
total_interest = interest
# ADDITIONAL CONTRIBUTION
total_result = form.cleaned_data['annual_additional_contribution']
# SET YEARLY RESULTS
yearly_results[i]['interest'] = round(total_interest, 2)
yearly_results[i]['total'] = round(total_result,2)
# CREATE CONTEXT
context = {
'total_result': round(total_result,2),
'yearly_results': yearly_results,
'number_of_years': int(form.cleaned_data['number_of_years'])
}
# RENDER THE TEMPLATE
return render(request, 'loancalculator/index.html', context)
else:
form = InvestmentForm()
return render(request, 'loancalculator/index.html', {'form':form})
index.html
{% extends 'loancalculator/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div >
<div >
<div >
<div >
<h1> Investment Calculator</h1>
<h5> Enter the details below to see your estimate</h5>
<form action="" method="POST">
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Calculate</button>
</form>
<br>
</div>
</div>
</div>
<div >
<div >
<div >
<h1>Investment Results</h1>
<h3> After {{ number_of_years }} years, your investment is worth ${{ total_result }}</h3>
<div >
<table >
<thead>
<tr>
<th scope="col">Year</th>
<th scope="col">Interest</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
{% for key, value in yearly_results.items %}
<tr>
<th scope="row">{{ key }}</th>
<td>{{ value.interest }}</td>
<td>{{ value.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}
CodePudding user response:
When you create the context, the value 'form' doesn't get set (views.py, under get())
CodePudding user response:
Two ways you can go about doing what you want as I see it:
Method 1
Use sessions to hold the data and then refeed it to the form using initial form values. This is probably the easiest since it most closely matches what you already have.
from django.shortcuts import render
from django.views import View
from .forms import InvestmentForm
class Index(View):
def get(self, request):
# Fill in the initial values on the unbound form:
initial = {
'starting_amount': request.session.get('starting_amount'),
'number_of_years': request.session.get('number_of_years'),
'return_rate': request.session.get('return_rate'),
'annual_additional_contribution': request.session.get('annual_additional_contribution'),
}
form = InvestmentForm(initial=intial)
return render(request, 'loancalculator/index.html', {'form': form})
def post(self, request):
form = InvestmentForm(request.POST)
if form.is_valid():
# After getting the cleaned_data, set a session variable to hold it
total_result = form.cleaned_data['starting_amount']
request.session['starting_amount'] = total_result
number_of_years = int(form.cleaned_data['number_of_years']
request.session['number_of_years'] = number_of_years
return_rate = form.cleaned_data['return_rate']
request.session['return_rate'] = return_rate
annual_additional_contribution = form.cleaned_data['annual_additional_contribution']
request.session['annual_additional_contribution'] = annual_additional_contribution
total_interest = 0
yearly_results = {}
for i in range(1, number_of_years 1)):
yearly_results[i] = {}
# CALCULATE THE INTEREST
interest = total_result * (return_rate / 100)
total_result = interest
total_interest = interest
# ADDITIONAL CONTRIBUTION
total_result = annual_additional_contribution
# SET YEARLY RESULTS
yearly_results[i]['interest'] = round(total_interest, 2)
yearly_results[i]['total'] = round(total_result,2)
# CREATE CONTEXT
context = {
'total_result': round(total_result,2),
'yearly_results': yearly_results,
'number_of_years': number_of_years)
}
# RENDER THE TEMPLATE
return render(request, 'loancalculator/index.html', context)
else:
form = InvestmentForm()
return render(request, 'loancalculator/index.html', {'form':form})
Method 2
From what you show here, anyway, you could just use JavaScript to do the calculations by grabbing the values directly from the DOM after they are entered, doing the calculations on the front end with JavaScript, and then fill in the values by targeting the locations where you want the results displayed in the DOM. No need for forms, no reloading of pages.