How to add two form fields (one shown and one not) to a model field

Viewed 23

I have a Spent model class that holds the name of where the user spent money at, how much, the reason as to why they spent, and a total amount spent. The total amount spent does not show up on the form in the template just the name, place and how much was spent (no need for the total amount to be shown). I'm having trouble figuring out how to update the total amount spent. I would like to have the total amount spent keep track of how much the user has spent in total.

modles.py

from django.db import models
from django.contrib.auth.models import User


class Bills(models.Model):
    name = models.CharField(max_length=25)
    amount = models.FloatField()
    due_date = models.DateField()
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class Budget(models.Model):
    income = models.FloatField(default=0.00)
    budget = models.FloatField(default=0.00)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.user.username


class Spent(models.Model):
    # I would like a way to the total amount here
    # to updated every time a user adds spent money
    # something along the lines of 
    # old_amount = self.total_spent
    # new_amount = self.amount
    # self.total_spent = old_amount + new_amount


    # Not sure if I do this here in the model or in the form or view
    # any help is greatly appreciated!!!!


    name = models.CharField(max_length=25)
    amount = models.FloatField(default=0.00)
    reason = models.TextField(default="")
    total_spent = models.FloatField(default=0.00)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.user.username

forms.py

from django import forms
from .models import Bills, Budget, Spent


class DateInput(forms.DateInput):
    input_type = 'date'


class AddBillForm(forms.ModelForm):
    class Meta:
        model = Bills
        fields = ['name', 'amount', 'due_date']

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter bill name'}),
            'amount': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter the bill amount ex: 250.00'}),
            'due_date': DateInput(attrs={'class': 'form-control'}),
        }


class UpdateBillForm(forms.ModelForm):
    class Meta:
        model = Bills
        fields = ['name', 'amount', 'due_date']

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'amount': forms.NumberInput(attrs={'class': 'form-control'}),
            'due_date': DateInput(attrs={'class': 'form-control'})
        }


class AddBudgetForm(forms.ModelForm):
    class Meta:
        model = Budget
        fields = ['income', 'budget']

        widgets = {
            'income': forms.NumberInput(attrs={'class': 'form-control'}),
            'budget': forms.NumberInput(attrs={'class': 'form-control'})
        }


class UpdateBudgetForm(forms.ModelForm):
    class Meta:
        model = Budget
        fields = ['income', 'budget']

        widgets = {
            'income': forms.NumberInput(attrs={'class': 'form-control'}),
            'budget': forms.NumberInput(attrs={'class': 'form-control'})
        }


class AddSpentForm(forms.ModelForm):

    class Meta:
        model = Spent
        fields = ['name', 'amount', 'reason']

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'amount': forms.NumberInput(attrs={'class': 'form-control'}),
            'reason': forms.Textarea(attrs={'class': 'form-control'})
        }

views.py

from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Bills, Budget, Spent
from .forms import AddBillForm, UpdateBillForm, AddBudgetForm, UpdateBudgetForm, AddSpentForm


class AddBillView(CreateView):
    model = Bills
    template_name = 'budget/add-bill.html'
    form_class = AddBillForm
    success_url = reverse_lazy('profile')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)


class UpdateBillView(UpdateView):
    model = Bills
    template_name = 'budget/update-bill.html'
    form_class = UpdateBillForm
    success_url = reverse_lazy('profile')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)


class DeleteBillView(DeleteView):
    model = Bills
    template_name = "budget/delete-bill.html"
    success_url = reverse_lazy('profile')


class CreateBudgetView(CreateView):
    model = Budget
    template_name = "budget/budget.html"
    form_class = AddBudgetForm
    success_url = reverse_lazy('profile')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)


class UpdateBudgetView(UpdateView):
    model = Budget
    template_name = "budget/update-budget.html"
    form_class = UpdateBudgetForm
    success_url = reverse_lazy('profile')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)


class AddSpentView(CreateView):
    model = Spent
    template_name = 'budget/add-spent.html'
    form_class = AddSpentForm
    success_url = reverse_lazy('profile')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)
1 Answers

This would be a good time for overriding the .save() method in the forms.py
I wasn't sure exactly how your models are connected.. But here's the broad strokes

class AddBillForm(forms.ModelForm):
    class Meta:
        model = Bills
        fields = ['name', 'amount', 'due_date']

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter bill name'}),
            'amount': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter the bill amount ex: 250.00'}),
            'due_date': DateInput(attrs={'class': 'form-control'}),
        }

    def save(self):
        obj = super(AddBillForm, self).save(commit=False)
        if commit:
            obj.save()

            # Get the Spent Obj
            spentObj = Spent.objects.get(name=self.cleaned_data.get('name'))
            # Update it
            spentObj.total_spent += self.cleaned_data.get('amount')
            spentObj.save()
            # ^ you could also update this with F('') statements!


class UpdateBillForm(forms.ModelForm):
    class Meta:
        model = Bills
        fields = ['name', 'amount', 'due_date']

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'amount': forms.NumberInput(attrs={'class': 'form-control'}),
            'due_date': DateInput(attrs={'class': 'form-control'})
        }

    def save(self):
        oldamt = obj.amount

        obj = super(AddBillForm, self).save(commit=False)

        if commit:
            obj.save()

            # I hope oldamt is still correct after the save
            the_change = self.cleaned_data.get('amount')-oldamt

            # Get the Spent Obj
            spentObj = Spent.objects.get(name=self.cleaned_data.get('name'))
            # Update it
            spentObj.total_spent += the_change
            spentObj.save()
Related