Calories Tracker Project — Round 3
We have a function that adds food entries. It validates the data. It timestamps automatically. It works.
What it doesn't do yet is loop. At breakfast alone you might log eggs, cheese, bread, and butter — four separate entries. So we wrap everything in a menu.
while True:
option = input("Choose option (1-Add, q-Quit): ")
# input always returns a string
if option == "1":
add_food_item()
print("Food log added successfully!")
elif option == "q":
break
else:
print("Invalid option!")
Simple. Clean. We can now add as many entries as we want — or as many as we actually consumed. The dictionary grows with each call. We can always come back to it.
Before we think about persistence — saving data so it survives after the program closes — we want to understand what we actually need from this data. Persistence without purpose is just storage. So first, let's think about reports.
Three come to mind naturally:
- A full history — everything logged, useful to share with a trainer, doctor, or nutritionist
- A 7-day summary — calories only, to check against a personal target
- A 7-day detailed view — what we actually ate, not just the numbers, useful for planning tomorrow's meals
We'll build all three. But we start with the one that feels most useful right now — the detailed 7-day view. And we start even simpler than that: today only.
# def add_food_item(): [...]
def last_days_details():
pass
pass keeps the function valid without doing anything. No errors, no output — just a placeholder we can build on.
def last_days_details():
# isolate today as a string — same format as the key, so we can compare
today_string = datetime.datetime.now().strftime("%Y-%m-%d")
for key in food_dict:
# the key format is "2025-04-02,14:32:11"
# split(",")[0] gives us just the date part
if today_string == key.split(",")[0]:
pass
The logic is there. Now we collect the matching entries into a new dictionary and return it.
def last_days_details():
today_string = datetime.datetime.now().strftime("%Y-%m-%d")
last_days_dict = {}
for key in food_dict:
if today_string == key.split(",")[0]:
last_days_dict[key] = food_dict[key]
return last_days_dict
Good. Now we extend it to 7 days. For that we need timedelta — also from the datetime module.
timedelta represents a duration — a difference between two dates. timedelta(days=1) is one day. Subtract it from today and you get yesterday. Subtract timedelta(days=6) and you get six days ago. It lets you move forward or backward in time by any amount, without manually calculating dates.
def last_days_details():
today = datetime.datetime.now()
last_days_dict = {}
for n in range(0, 8):
reference_day = (today - datetime.timedelta(days=n)).strftime("%Y-%m-%d")
for key in food_dict:
if reference_day == key.split(",")[0]:
last_days_dict[key] = food_dict[key]
return last_days_dict
range(0, 8) gives us 0 through 7 — today plus the previous 6 days. For each, we build the date string and check it against every key in the dictionary. Matches go into last_days_dict.
Now we need to display it. We build a print function:
def print_details(food_log):
for key in food_log:
print(f"{key.split(',')[0]} - {food_log[key][0]} - {food_log[key][1]}{food_log[key][2]} - {food_log[key][3]} kcal")
Let's unpack what's happening here. key.split(',')[0] gives us the date — we drop the time, we don't need it for display. food_log[key] is the list of values: index 0 is the name, index 1 is the quantity, index 2 is the measure, index 3 is the calories. We stitch them together with an f-string — one readable line per entry. Something like:
2025-04-02 - Chicken Breast - 200.0g - 175 kcal
We can call them separately — or we can fold last_days_details() inside print_details() to keep the call simple:
def print_details():
food_log = last_days_details()
for key in food_log:
print(f"{key.split(',')[0]} - {food_log[key][0]} - {food_log[key][1]}{food_log[key][2]} - {food_log[key][3]} kcal")
This goes into the menu as option 2:
while True:
option = input("Choose option (1-Add, 2-Show food details, q-Quit): ")
if option == "1":
add_food_item()
print("Food log added successfully!")
elif option == "2":
if len(last_days_details()):
print_details()
else:
print("No data available.")
elif option == "q":
break
else:
print("Invalid option!")
if len(last_days_details()) — len() returns the number of entries in the dictionary. If it's 0, the condition is False and we print "No data available." instead of running the print function on an empty result. It's a simple guard — don't try to display what isn't there.
The structure now looks like this:
# def add_food_item(): [...]
# def last_days_details(): [...]
# def print_details(): [...]
while True:
option = input("Choose option (1-Add, 2-Show food details, q-Quit): ")
if option == "1":
add_food_item()
print("Food log added successfully!")
elif option == "2":
if len(last_days_details()):
print_details()
else:
print("No data available.")
elif option == "q":
break
else:
print("Invalid option!")
Here's what a populated log looks like after a few entries:
2025-04-02 - Chicken Breast - 200.0g - 175 kcal
2025-04-02 - White Rice - 100.0g - 130 kcal
2025-04-02 - Greek Yogurt - 150.0g - 88 kcal
2025-04-03 - Oats - 80.0g - 297 kcal
2025-04-03 - Banana - 1.0pcs - 89 kcal
Date, name, quantity with measure, calories. Everything we decided mattered — nothing we decided didn't.
We take data in. We filter it. We display it. All by our own rules.
In survival training, there's a moment after you light your first fire. Not the moment you strike the spark. The moment the flame holds on its own. That's where we are.
We didn't just write code. We built something that works. Next, we make it last.