Paty Pizá
Paty Pizá

Reputation: 19

Sum the values of a form and add that result to the database

I want to make a form that has 3 number radio values, supposedly look like this:

enter image description here

And I'd like for those 3 values to sum and display the sum of those values to then save them into the database.

forms.py:

class FormTest(forms.Form):
    CHOICES = [
        ('0', '0'),
        ('1', '1'),
        ('2', '2'),
        ('3', '3'),
        ('4', '4'),
        ('5', '5'),        
    ]
    num1 = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
    num2 = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
    num3 = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
    total = num1 + num2 + num3

models.py:

class Test(models.Model):
    num1 = models.IntegerField()
    num2 = models.IntegerField()
    num3 = models.IntegerField()

class Dato(models.Model):
    dato = models.IntegerField()

views.py:

def formtest(request):
    """
    if request.method == 'GET':
        return render(request, 'testform.html', {
        'form': FormTest()
    })
    else:
        Test.objects.create(
            num1=request.POST["num1"],
            num2=request.POST["num2"],
            num3=request.POST["num3"]
        )
        return redirect('forms')
    """
    if request.method == 'GET':
        return render(request, 'testform.html', {
        'form': FormTest(),
    })
    else:
        Dato.objects.create(
            dato=request.POST['dato']
        )
        return redirect('forms')

testform.html:

{% extends 'layouts/base.html' %}
{% block content %}

    <h1>Test Form</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button>Save</button>        
    </form>

    {{ totalsum }}

{% endblock %}

urls.py:

from django.urls import path
from . import views

urlpatterns = [
    #path('', views.index),
    path('', views.index, name="index"),
    path('about/', views.about, name="about"),
    path('hello/<str:username>', views.hello, name ="hello"),
    path('projects/', views.projects, name="projects"),
    path('tasks/', views.tasks, name="tasks"),
    path('create_task/', views.create_tasks, name="create_task"),
    path('create_projects/', views.create_project, name="create_projects"),
    path('formtest', views.formtest, name="forms")
]

I know I'm not allowed to sum ChoiceFields on its own but I have no idea what to actually do to make it work, I guess I could try a Javascript but I don't know how to incorporate it, correctlly... Help? Please?

Upvotes: 0

Views: 36

Answers (1)

Niko
Niko

Reputation: 3798

I just could not reproduce the visual in the same way, by using a custom styling in the template, although it is pretty close.

To make it work you need to retrieve the data from the request.POST (in this case via django form). To save the object you can just create an object instance using the form cleaned_data kwargs:

Test.objects.create(**form.cleaned_data)

which is equivalent to:

Test.objects.create(
    num1=form.cleaned_data.get('num1'), 
    num2=form.cleaned_data.get('num2'), 
    num3=form.cleaned_data.get('num3')
)

But, to do an operation with the data, first, you need to retrieve it from the form's cleaned_data object. This data comes in string format, so it is necessary to parse / convert into an integer in order to do the wanted operation:

number1 = int(form.cleaned_data.get('num1'))
number2 = int(form.cleaned_data.get('num2'))
number3 = int(form.cleaned_data.get('num3'))
total = number1 + number2 + number3

One possible solution:

models.py

from django.db import models

class Test(models.Model):
    num1 = models.IntegerField()
    num2 = models.IntegerField()
    num3 = models.IntegerField()

    # Not really necessary, just to show on template
    def __str__(self):
        total = self.num1 + self.num2 + self.num3
        return f'{self.num1} + {self.num2} + {self.num3} = {total}'

forms.py (Optionally, you can explore model form for a cleaner solution)

from django import forms

CHOICES = [
        ('0', '0'),
        ('1', '1'),
        ('2', '2'),
        ('3', '3'),
        ('4', '4'),
        ('5', '5'),        
    ]

class SimpleForm(forms.Form):
    num1 = forms.ChoiceField(
        required=True,
        widget=forms.RadioSelect({'class': 'myfieldclass'}),
        choices=CHOICES,
        initial=0
    )

    num2 = forms.ChoiceField(
        required=True,
        widget=forms.RadioSelect({'class': 'myfieldclass'}),
        choices=CHOICES,
        initial=0
    )

    num3 = forms.ChoiceField(
        required=True,
        widget=forms.RadioSelect({'class': 'myfieldclass'}),
        choices=CHOICES,
        initial=0
    )

views.py

from django.shortcuts import render
from .forms import SimpleForm
from .models import Test

def select_number(request):
    total = None
    tests = Test.objects.all()

    if request.method == 'POST':
        form = SimpleForm(request.POST)
        if form.is_valid():
            # Save obj
            Test.objects.create(**form.cleaned_data)
            # cast data to interger, to show current test result
            number1 = int(form.cleaned_data.get('num1'))
            number2 = int(form.cleaned_data.get('num2'))
            number3 = int(form.cleaned_data.get('num3'))
            total = number1 + number2 + number3
    else:
        form = SimpleForm()
    context = {'form': form, 'total': total, 'tests': tests}
    return render(request, 'select_number.html', context)

select_number.html

{% extends 'base.html' %}

{% block content %}
    <style>
        .myfieldclass {
            display: flex;
            flex-flow: row nowrap;
        }
    </style>
    <form action="{% url 'core:select-number'%}" method="post"> 
        {% csrf_token %}
        <table>
            {{form}}
        </table>
        <button type="submit">Sum Up</button>
    </form>
    <br>
    {% if total %}
        The total of the current sum is {{total}}
    {% endif %}
    <hr>
    <h2>My tests list</h2>
    {% for test in tests %}
        {{test}}<br>
    {% endfor %}
{% endblock content %}

urls.py

from django.urls import path
from core import views

app_name = 'core'

urlpatterns = [
    path('select/number/', views.select_number, name='select-number'),
]   

Of course, it is possible to do all of that with Javascript using AJAX. Usually used when you do not want to your page to be entirely reloaded when sending a request to a view.

Upvotes: 1

Related Questions