ATM machine demo with Python and Django

This is a long post. The most important information is at the top and gradually progresses to less and less relevant information. So you don’t have to read all of it. Just start reading at the top and then when you get bored, simply discard the rest.

I’m trying to build a rudimentary ATM machine demo with Python and Django.

Here is a screenshot of my site in its current form.

The intended basic functionality I am trying to create right now is to have the web visitor (banking client) enter the amount of cash in the input field and then click: “Deposit” or ”Withdraw”. Say for example the client deposits $20, the amount should appear in the HTML table under the “Credits” column and the “Running Balance” column should reflect that as well, like anyone would expect a typical ATM and basic accounting ledger to behave. The problem is, when a web visitor enters an amount and clicks “Deposit”, nothing happens.

I know the main problem is clearly with my views.py:

from django.shortcuts import render
from telagents.models import Account
 
def index(request):
   balances = 0
   withdrawals = 0
   deposits = 0
   amounts = 0
   data = Account.objects.all().order_by('-inception_date')
   context = {'data':data,'withdrawals':withdrawals,'deposits':deposits,'amount':amounts, 'balances': balances,} # initialize context var to be updated after math operations
   if 'deposits' in request.POST:  
       balances = balances + amounts
       context.update({'balances': balances,})
   elif 'withdrawals' in request.POST:
       balances  = balances - amounts
       context.update({'balance': balances,})   
   return render(request, "telagents/home.html", context)

As you can see above, I declare (initialize) the numerical variables each to integer 0. Next I establish the context variable as a dictionary. I am then trying to use conditional logic to catch cases when the template receives a POST request from the input form from the web visitor. But instead, it’s as if the deposits antecedent isn’t getting triggered so Django is effectively ignoring it and continues on to the next operation ultimately skipping down to the bottom and just passing in the original context dictionary with the variables assigned to 0. That’s not how I want my app to behave. Instead I want Django to receive a deposit from the user as a POST request and then process the basic mathematical operation (add the amount for a Deposit) and then update the balance according to client input and serve the updated balance back into the HTML table in the template. To achieve that desired outcome, I am all out of ideas on what to try next. Can anyone provide some guidance or further insight here?

Here is my template: home.html (which has its own set of issues that I already have some insight into discussed afterwards):

 <body>
{% block content %}
 
<br><br>
 
{% for data_obj in data %}
   <center>
   Client Name : {{data_obj.first_name}} {{data_obj.last_name}}
       <br>
   Bank Account Number : {{data_obj.account_number}}
       <br>       
   Interest Rate : {{data_obj.interest}} %
   </center>
{% endfor%}
 
<br><br>
 
<center>
<form action="{% url 'index' %}" method="post"> {% csrf_token %}
  <!-- <label for="fname">Merchant Name:</label>
   <input type="text" id="fname" name="fname"><br><br> -->
  <label for="amount">Amount:</label>
  <input type="number" id="amount" name="amounts"><br><br>
 
 <input type="submit" value="Deposit" name="deposits">
  <input type="submit" value="Withdraw"name="withdrawals">
 </form>
</center>
<br>
 
<!-- HTML Code: Place this code in the document's body (between the 'body' tags) where the table should appear -->
<center>
<table class="GeneratedTable">
   <thead>
   <tr>
     <th>Type</th>
     <th>Timestamp</th>
     <th>Trans ID #</th>
     <th>Debits</th>
     <th>Credits</th>
     <th>Running Balance</th>
   </tr>
 </thead>
 <tbody>
   <tr>
  
     <td>Cell</td>
    
     {% for data_obj in data %}
     <td>{{ data_obj.transaction_time_stamp }}</td>
        {% endfor %}    
    
     <td>Cell</td>
    
     <td>{{ withdrawals }}</td>
 
     <td>{{ deposits }}</td>
    
     <td>{{ balances }} </td>
 
   </tr>
 </tbody>
</table>
<!-- Codes by Quackit.com -->
 
 
 {% endblock %}
</center>
 

The problem with the above template is the withdrawals, deposits, and balances. They are just empty variables. They are not dynamic. In an effort to make them dynamic, I tried wrapping them around with variations of Jinja for loops and conditionals but no matter which combination I tried, I couldn’t get the user input to reflect inside the right columns in the table.

I’ve got my models.py configured. For what it’s worth (and for general reference), here it is:

from django.db import models
from datetime import datetime
#from pytz import timezone
import decimal
from decimal import Decimal
from random import randint
 
 
class Account(models.Model):
   interest = models.DecimalField(max_digits=6, decimal_places=3) # Decimal('0.005') # Percent
   inception_date = models.DateTimeField('Client since (inception date)')
   first_name = models.CharField(max_length=30)
   last_name = models.CharField(max_length=30)
   account_number = models.BigIntegerField()
 
   def transaction_time_stamp(self):
       return self.inception_date.strftime("%A %d %B %Y @ %I:%M:%S %p")
  
   def __str__(self):
       return f'{self.first_name} {self.last_name}'

This project started out as an exercise for a hobby course on Udemy by Fred Baptiste that I am taking on Python OOP (working CLI script below) which I decided to port to Django:

from datetime import datetime
from pytz import timezone
import decimal
from decimal import Decimal
from random import randint
 
class TimeZone:
  
   def __init__(self):
       self.selection = int(input("Howdy! Make your time zone selection: \n 1: Los Angeles \n 2: London \n 3: Shanghai \n 4: Sydney \n 5: Rio de Janeiro \n"))
       self.locality = {
           1: "US/Pacific", # Los Angeles
           2: "Europe/London", # London
           3: "Asia/Shanghai", # Shanghai
           4: "Australia/Sydney", # Sydney
           5: "Brazil/East", # Rio de Janeiro
       }  
       self.tz = datetime.now(timezone(self.locality[self.selection]))
       self.readable_format = '%Y-%m-%d %H:%M:%S %Z%z'
       print(f'The date and time: {self.tz.strftime(self.readable_format)}')
       self.transaction_time_id_format = '%Y%m%d%H%M%S'
       print(f'The date and time condensed: {self.tz.strftime(self.transaction_time_id_format)}')
  
   def condensed(self):
      return f'{self.tz.strftime(self.transaction_time_id_format)}'
 
class Account:
  
   interest = Decimal('0.005') # Percen t
 
   def __init__(self, first_name, last_name, account_num=10000001, starting_balance=0.00):
       self.first_name = first_name
       self.last_name = last_name
       self.full_name = f'{first_name} {last_name}'
       self.account_num = randint(9999999,99999999)
       self.balance = round(Decimal(starting_balance),2)
       self.transaction_id = randint(101,999)
       self.tzone = TimeZone()
 
   def deposit(self, amount):
       self.balance += round(Decimal(amount),2)
       self.transaction_id += randint(101,999) - randint(101,999)
       return f'D-{self.account_num}-{self.tzone.condensed()}-{self.transaction_id}'
  
   def withdraw(self, amount):
       if amount > self.balance:        
           self.transaction_id += randint(101,999) - randint(101,999)
           print(f'X-{self.account_num}-{self.tzone.condensed()}-{self.transaction_id}')
           raise ValueError('Transaction declined. Insufficient funds. Please deposit some more $$$ first.')
          
       self.balance -= round(Decimal(amount),2)
       self.transaction_id += randint(101,999) - randint(101,999)
       return f'W-{self.account_num}-{self.tzone.condensed()}-{self.transaction_id}'
 
   def pay_interest(self):
       monthly_rate = self.interest/12
       monthly_sum = monthly_rate * self.balance
       self.transaction_id += randint(101,999) - randint(101,999)
       print(f'I-{self.account_num}-{self.tzone.condensed()}-{self.transaction_id}')
       return round(Decimal(monthly_sum, + self.balance), 2)
 
   def __repr__(self):
       """Return a string that represents the account."""
       return f"{self.__class__.__name__}({self.last_name}, {self.first_name}, balance={self.balance})"

Below are the original specs for the above completed exercise. My goal for my Django ATM machine is to reach feature parity.

SPECS

Here are the basic specs, functionality, and characteristics as outlined by course instructor Fred Baptiste:

  • accounts are uniquely identified by an account number (assume it will just be passed in the initializer)
  • account holders have a first and last name
  • accounts have an associated preferred time zone offset (e.g. -7 for MST)
  • balances need to be zero or higher, and should not be directly settable.
  • but, deposits and withdrawals can be made (given sufficient funds)
    • if a withdrawal is attempted that would result in negative funds, the transaction should be declined.
  • a monthly interest rate exists and is applicable to all accounts uniformly. There should be a method that can be called to calculate the interest on the current balance using the current interest rate, and add it to the balance.
  • each deposit and withdrawal must generate a confirmation number composed of:
  • the transaction type: D for deposit, and W for withdrawal, I for interest deposit, and X for declined (in which case the balance remains unaffected)
    • the account number
    • the time the transaction was made, using UTC
    • an incrementing number (that increments across all accounts and transactions)
    • for (extreme!) simplicity assume that the transaction id starts at zero (or - whatever number you choose) whenever the program starts
  • the confirmation number should be returned from any of the transaction methods (deposit, withdraw, etc)
  • create a method that, given a confirmation number, returns:
    • the account number, transaction code (D, W, etc), datetime (UTC format), date time (in whatever timezone is specified in te argument, but more human readable), the transaction ID
    • make it so it is a nicely structured object (so can use dotted notation to access these three attributes)
    • I purposefully made it so the desired timezone is passed as an argument. Can you figure out why? (hint: does this method require any information from any instance?)

So just looking at the index view, you’re not saving the entered data anywhere. Yes, you’re updating the context for the template, but that information is going to be lost on the next call to that view.

Also, you’re not retrieving the data from the request. You’re checking to see if the field is in the POST, but then you’re not accessing it.

My first suggestion is that you review the docs at Working with forms | Django documentation | Django and Creating forms from models | Django documentation | Django to refresh yourself on the interaction between views, forms, and templates.

Hello, Friends!

I’m back. Thank you @KenWhitesell for your reply.

The Django doc on forms was especially helpful. In particular I leveraged the sections on views and field data. Following along with these docs closely and based on what I learned, I rebuilt my codebase. I created forms.py and completely rewrote both my template and views.py from scratch. Now I am getting a key error. I figure the solution I need is far more trivial today than last week but at this point I am bashing my head against the wall and stabbing in the dark.

I’ll share my code, along with the traceback and explain what I think is going on which hopefully will be enough for you people to recommend what I could try next.

forms.py:

from django import forms

class AmountForm(forms.Form):
    amount = forms.DecimalField(label='Amount', max_digits=10, decimal_places=2)

As you can see above, there is only one field I’ve declared: amount. This is the only information the web visitor can input when they visit the site. My form has two input buttons (‘Withdraw’ and ‘Deposit’) but when they are pressed by the web visitor, Django redirects the amount value back for processing by the views (below) which should then in turn store it in the database and then be presented back to the web visitor with an updated balance variable in the table when Django re-serves the template.

views.py:

from django.shortcuts import render
from django.http import HttpResponseRedirect,HttpResponse
from .models import Account
# Create your views here.
from .forms import AmountForm

def index(request):
    # Starting balance variable initialization:
    balance = 0 
    context = {'balance': balance}
    # Import `Account` model data:
    data = Account.objects.all().order_by('-inception_date')
    # If this is a POST request we need to process the form data:
    if request.method == 'POST':
        # Create a form instance and populate it with data from the request:
        form = AmountForm(request.POST)
        # Check whether it's valid:
        if form.is_valid():
            # Process the data in form.cleaned_data as required:
            deposit = form.cleaned_data['deposit']
            withdraw = form.cleaned_data['withdraw']
            amount = form.cleaned_data['amount']
            if deposit:
                balance = balance + amount
                context.update({'balance': balance,})
            elif withdraw:
                balance = balance - withdraw
                context.update({'balance': balance,})
            # Redirect to a new URL:
            return render(request, 'telagents/home.html', {'form': form, 'data':data, 'context': context,})

    # If a GET (or any other method) we'll create a blank form:
    else:
        form = AmountForm()

    return render(request, 'telagents/home.html', {'form': form, 'data':data, })

As you can see in the above views, I’ve retained and added annotations line-by-line to help document what is going on. When Django checks for the validity of the form, assuming it is valid, received (and cleaned) data (deposit, withdraw, amount) is assigned to variables. If deposit is triggered, then the basic mathematical operation takes place (increase the size of balance by the amount entered by the web visitor). And then I attempt to update the context dictionary variable with the new balance amount. Finally, the request is rendered for the home template while passing in the form, data, and context information. That’s ‘air tight’. That’s my very best effort up to this point at rewriting a proper views.py based on the documentation.

templates/telagents/home.html:

 <body>
  {% block content %}

    <br><br>

{% for data_obj in data %}
    <center>
    Client Name : {{data_obj.first_name}} {{data_obj.last_name}}
        <br>
    Bank Account Number : {{data_obj.account_number}}
        <br>
    Client Since : {{ data_obj.inception_date }}
        <br>        
    Interest Rate : {{data_obj.interest}} %
    </center>
{% endfor%}

<br><br>

<center>
<form action="{% url 'index' %}" method="post"> 

    {% csrf_token %}
    {{ form }}
  <input type="submit" value="Deposit" name="deposit" >
  <input type="submit" value="Withdraw" name="withdraw">
</form>
</center>
<br>

<center>
<table class="GeneratedTable">
    <thead>
    <tr>
      <th>Type</th>
      <th>Timestamp</th>
      <th>Trans ID #</th>
      <th>Debits</th>
      <th>Credits</th>
      <th>Running Balance</th>
    </tr>
  </thead>
  <tbody>
    <tr>
    {% for trans_objs in context %}
      <td>Cell</td>
            
      <td>Cell</td>
      
      <td>Cell</td>
      
      <td>{{ trans_objs.withdraw }}</td>

      <td>{{ trans_objs.deposit }}</td>
      
      <td>{{ trans_objs.balance }} </td>
          {% endfor %}     
    </tr>
  </tbody>
</table>

</center>

{% endblock %}

</body>

As you can see above, I’ve used Django’s very easy and convenient instance of {{ form }} for easy deployment of HTML forms. I’ve got the CSRF token in place. I’ve got the two input tags for the withdraw and deposit buttons. Finally in the table, I’ve completely reworked the Jinja for loop to output the withdraw, deposit, and balance data points.

Here is my traceback:

System check identified no issues (0 silenced).
May 20, 2022 - 17:36:04
Django version 4.0.4, using settings 'Django_ATM_OOP_demo.settings'
Starting development server at http://localhost:9000/
Quit the server with CONTROL-C.
Internal Server Error: /
Traceback (most recent call last):
File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/telagents/views.py", line 20, in index
deposit = form.cleaned_data['deposit']
KeyError: 'deposit'

This error is pointing to line 20 of my views.py where the deposit variable is declared referencing where Django is trying to extrapolate the deposit information as cleaned_data. That’s all I understand about that.

This is the point where I ask for more insight from the community.

What else is this traceback trying to say? I suppose a good question for me to ask is which Django doc do I need to review next? Although that question is kind of silly because I think I kind of already know the answer to that question because it will likely be the same as before: Working with forms | Django documentation | Django

I am just missing a specific passage that I need to review again.

Is there any other advice you people could provide in terms of what I might need to change in my template, views, or forms to resolve this KeyError and enable my web app to properly process the data entry made by my web visitors?

For what it is worth and for those who may be interested, here is my full source code on GitHub (working branch): GitHub - enoren5/Django_ATM_OOP_demo at reviewing_forms_and_model_docs

edit: sp

Your form consists of one field - amount. There is no field named deposit or withdraw in the form.

That is the cause of your key error.

The value of the submit button is not populated in the form - it’s accessible directly in the request.POST object.

For example:

if 'deposit' in request.POST:  # The Deposit button was pressed

Side note: You can also use the same name for the two purposes.
example:

  <input type="submit" value="Deposit" name="transaction" >
  <input type="submit" value="Withdraw" name="transaction">

Would let you write:

if request.POST['transaction'] == 'Deposit':
and
if request.POST['transaction'] == Withdraw':

I’m beginning to understand. I actually originally had deposit and withdraw variables declared inside the forms.py class. Here it is with them commented out:

from django import forms
 
class AmountForm(forms.Form):
   amount = forms.DecimalField(label='Amount', max_digits=10, decimal_places=2)
   ''' deposit = forms.DecimalField(label='Deposit', max_digits=10, decimal_places=2)
    withdraw = forms.DecimalField(label='Withdraw', max_digits=10, decimal_places=2)'''

But I get what you are saying now with the deposit/withdraw buttons not being actual fields. These buttons are accessible directly in the request.POST object. Therefore, I will keep these lines commented out or delete them altogether. I commented out the deposit and withdraw references in the form validation check in views.py, included below.

Based on your feedback, for the two input names, I removed “deposit” and “withdraw” and in their place I now have, “transaction”. Therefore here is what the form in my template looks like now:

<center>
<form action="{% url 'index' %}" method="post">
 
   {% csrf_token %}
   {{ form }}
 <input type="submit" value="Deposit" name="transaction" >
 <input type="submit" value="Withdraw" name="transaction">
</form>
</center>

Next you make a very import suggestion for the correct post request conditional which switches between Deposit and Withdraw POST requests:

Keeping that in mind, here is my index function in full now:

def index(request):
   # Starting balance variable initialization:
   balance = 0
   context = {'balance': balance}
   # Import `Account` model data:
   data = Account.objects.all().order_by('-inception_date')
   # If this is a POST request we need to process the form data:
   if request.method == 'POST':
       # Create a form instance and populate it with data from the request:
       form = AmountForm(request.POST)
       # Check whether it's valid:
       if form.is_valid():
           # Process the data in form.cleaned_data as required:
           amount = form.cleaned_data['amount']
           # deposit = form.cleaned_data['deposit']
           # withdraw = form.cleaned_data['withdraw']           
           if request.POST['transaction'] == 'Deposit':
               balance = balance + amount
               context.update({'balance': balance,})
           if request.POST['transaction'] == 'Withdraw':
               balance = balance - amount
               context.update({'balance': balance,})
           # Redirect to a new URL:
           return render(request, 'telagents/home.html', {'form': form, 'data':data, 'context': context,})
 
   # If a GET (or any other method) we'll create a blank form:
   else:
       form = AmountForm()
 
   return render(request, 'telagents/home.html', {'form': form, 'data':data, })

All of the above integrates @KenWhitesell’s suggestions as best I can and is the latest state of my forms.py, home.html (template), and views.py.

Even witht he above changes, I am now encountering a traceback which points to a data structure Dictionary error like before, but this time it says: MultiValueDictKeyError. Here is the traceback in full:

Internal Server Error: /
Traceback (most recent call last):
  File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/venv/lib/python3.10/site-packages/django/utils/datastructures.py", line 84, in __getitem__
    list_ = super().__getitem__(key)
KeyError: 'transaction'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/telagents/views.py", line 23, in index
    if request.POST['transaction'] == 'Deposit':
  File "/home/<user>/dev/projects/python/2018-and-2020/Django_ATM_OOP_demo/venv/lib/python3.10/site-packages/django/utils/datastructures.py", line 86, in __getitem__
    raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'transaction'
[21/May/2022 10:56:10] "POST / HTTP/1.1" 500 80611

This error highlights line 23 in views.py which is this one:

if request.POST['transaction'] == 'Deposit':

That’s the line that @KenWhiteSell recommended. So I have clearly transcribed it incorrectly and misunderstood.

My understanding is that this line evaluates the condition where if there is a POST request for when the input button named “transaction” and has a value of “Deposit” is triggered by the web visitor. If that condition (antecedent) evaluates to True, then Python proceeds to the next line (to executre the consequent) to perform the mathematical operation (adding the entered amount into the form to the running balance) and then finally update the context variable (a Dictionary). That’s all I got.

What am I missing now?

Thank you Ken for your help and patience so far.

Or there’s something else happening.

That error is saying that there’s no key ‘transaction’ in the POST object.

Is there another submit button anywhere in your form? Is there any way that that form can be submitted without selecting one of those two buttons?

If there’s nothing obvious like that, you can start to chase this down by adding a print(request.POST) statement immediately before the form = AmountForm(request.POST) line. This will let you visually verify what’s being submitted in the POST object.

Thanks, Ken! I appended a print(request.POST) statement inside my index views function and presto, it revealed some stale input from my previous session prior to making the recent changes:

System check identified no issues (0 silenced).
May 21, 2022 - 12:08:41
Django version 4.0.4, using settings 'Django_ATM_OOP_demo.settings'
Starting development server at http://localhost:9000/
Quit the server with CONTROL-C.
<QueryDict: {'csrfmiddlewaretoken': ['<redacted>'], 'amount': ['111'], 'deposit': ['111'], 'withdraw': ['22', 'Withdraw']}>

So I figured the old data was being retained in a cookie or something. When I deleted the session cookies in my browser, I recieved a CSRF token error. My solution was to exit the server and re-run it on a different port. Now it runs with expected POST request data showing! See here:

<QueryDict: {'csrfmiddlewaretoken': ['<redacted>'], 'amount': ['1112.22'], 'transaction': ['Withdraw']}>

The problem I am setting out to tackle next is the fact that the updated running balance isn’t showing when Django re-serves the template. Here is what my web page looks like now. As you can see, in the box to the right and at the bottom is empty.

Instead I was intending to have the balance change dynamically every time a web visitor makes a deposit or withdrawal.

I fully understand that since I haven’t set up Django’s form models (as recommended by Ken previously), I can’t expect my site to save the data with each transaction. I have some more work to do there. But at the very least (temporarily for now) I’d just like to see if I can get Django to serve the sum of the amount passed into the form when added to the starting $0 balance (as intended in my views.py) when the web visitor enters an amount and clicks the “Deposit” button.

Here is the HTML table and Jinja for loop inside my template home.html:

<table class="GeneratedTable">
    <thead>
    <tr>
      <th>Type</th>
      <th>Timestamp</th>
      <th>Trans ID #</th>
      <th>Debits</th>
      <th>Credits</th>
      <th>Running Balance</th>
    </tr>
  </thead>
  <tbody>
    <tr>
    
    {% for trans_objs in context %}
      <td>Cell</td>            
      <td>Cell</td>      
      <td>Cell</td>      
      <td>{{ trans_objs.withdraw }}</td>
      <td>{{ trans_objs.deposit }}</td>      
      <td>{{ trans_objs.balance }} </td>
    {% endfor %}     

    </tr>
  </tbody>
</table>

edit: grammar + sp

Here is my latest views function:

def index(request):
   # Starting balance variable initialization:
   balance = 0
   context = {'balance': balance}
   data = Account.objects.all() 
   myaccount = Account.objects.get(id=1)
   print(request.POST)
   if request.method == 'POST':
       form = Transactions(request.POST)
       if form.is_valid():
           print(form)
           amount = form.cleaned_data['amount']
           if request.POST['transaction'] == 'Deposit':
               balance = balance + amount
               context.update({'balance': balance,})
           if request.POST['transaction'] == 'Withdraw':
               balance = balance - amount
               context.update({'balance': balance,})
           myaccount.balance = balance
           myaccount.save()
           return render(request, 'telagents/home.html', {'form': form, 'data':data, 'context': context,})
 
   else:
       form = AmountForm()
 
   return render(request, 'telagents/home.html', {'form': form, 'data':data, })

The crucial changes above is the instantiation of the Account class object during initialization with the .get query set to the only id row entry in the db. I then refer to this object towards the end of the algorithm where I apply the balance input collected from the POST request to the balance attribute and then save it to myaccount.

Any further commentary to clarify that understanding from other forum members might help.

So I accomplished what I intended to in my post above. By that I mean, when a web visitor lands on the web page now and they enter a dollar amount and click “Deposit”, the balance field in the ledger updates to reflect the amount entered.

The problem to solve next is that my views.py function algorithm doesn’t track a running tally with subsequent deposits. When a web visitor enters a second deposit amount, it just overwrites the former balance. The next step for me to take is to fix this.

I had help from a friend to come up with my revised views.py but I refined it further based on a free mini crash course which teaches how to first use a GUI sqlite browser utility and then proceeds to cover querying db.sqlite3 from Python REPL integrated with a basic Django test project. The course refers to Django docs:

1 Like