Full Control: Updating and Deleting Inventory
The Big Idea
This chapter completes our core application logic by adding the final two essential operations of data management: updating an existing product's details and deleting a product from the inventory.
Roadmap
Introducing CRUD: We'll learn about CRUD (Create, Read, Update, Delete), the four fundamental operations of any data-driven application.
The Helper Function Pattern: A professional technique for avoiding code repetition. We'll build a
find_product
helper function that both ourupdate
anddelete
functions will use.Searching with
enumerate
: Learn how to use theenumerate
function to get both the index and the item from a list while looping.Building the
update_product
Function: Create the logic to find an item, ask for new values, and modify the dictionary in place.Building the
delete_product
Function: Create the logic to find an item and remove it from the inventory list using the.pop()
method.Expanding the Main Menu: Integrate the new Update and Delete options into our application's main loop.
Full Chapter Content
CRUD: The Four Pillars of Data
So far, our application can Create new products (with add_product
) and Read them (with display_inventory
). These are two of the four fundamental operations of data management, collectively known as CRUD:
Create: Add new data.
Read: Retrieve data.
Update: Modify existing data.
Delete: Remove existing data.
To make our application complete, we need to implement Update and Delete.
A Professional Technique: The Helper Function
Both updating and deleting a product start with the exact same first step: finding the product in our inventory list. Instead of writing the finding logic twice (violating the DRY principle), we'll create a single, reusable helper function called find_product
.
This function will ask the user for a product name, loop through the inventory to find it, and then return the product's dictionary and its index (position) in the list.
To do this efficiently, we'll use a new tool: enumerate()
. When you use enumerate
in a for
loop, it gives you back two values on each iteration: the index of the item, and the item itself.
for index, item in enumerate(inventory_list):
Now, let's build our new features step-by-step.
Step 1: Create the find_product
Helper Function
This function's only job is to search. It is a tool for our other functions to use.
Add this new function to the "Function Definitions" section of your main.py
file. It's good practice to place helper functions before the main functions that use them.
def find_product(inventory_list):
"""
Helper function to find a product by name and return its index and data.
"""
search_name = input("Enter the name of the product to find: ")
for index, product in enumerate(inventory_list):
if product['name'].lower() == search_name.lower():
return index, product # Return both the index and the product dict
return None, None # Return None if not found
What's New Here?
enumerate(inventory_list)
: Provides both the index and the product dictionary for each item in the list..lower()
: We compare both the stored name and the search term in lowercase to make the search case-insensitive ('laptop' will find 'Laptop').return index, product
: If we find a match, we return two values at once.return None, None
: If the loop finishes without finding a match, we returnNone
(a special Python value representing "nothing") for both values.
Step 2: Create the update_product
Function
This function will orchestrate the update process. It will call our new helper function first.
Add this function to main.py
:
def update_product(inventory_list, currency_symbol):
"""Finds a product and allows the user to update its details."""
index, product = find_product(inventory_list)
if product is None:
print("Product not found.")
return
print(f"Found: {product['name']}. Current quantity: {product['quantity']}, Current price: {currency_symbol}{product['price']}")
# Get new values, allowing user to press Enter to skip a change
new_quantity_str = input(f"Enter new quantity (or press Enter to keep {product['quantity']}): ")
new_price_str = input(f"Enter new price (or press Enter to keep {product['price']}): ")
if new_quantity_str:
product['quantity'] = int(new_quantity_str)
if new_price_str:
product['price'] = float(new_price_str)
print(f"SUCCESS: '{product['name']}' has been updated.")
What's New Here?
It first calls
find_product()
and checks if the result wasNone
.It cleverly allows the user to update only what they need. If the user just presses Enter, the input string is empty, the
if
condition is false, and the old value is kept.
Step 3: Create the delete_product
Function
This function will also use our helper, but its action is simpler: remove the item from the list. We do this with the .pop()
list method, which removes an item at a specific index.
Add this final function to main.py
:
def delete_product(inventory_list):
"""Finds and deletes a product from the inventory."""
index, product = find_product(inventory_list)
if product is None:
print("Product not found.")
return
product_name = product['name'] # Store name for the message
inventory_list.pop(index)
print(f"SUCCESS: '{product_name}' has been deleted from the inventory.")
Step 4: Update the Main Menu
The last step is to add the new options to our while
loop so the user can actually use our new functions.
Modify the main loop at the end of main.py
:
# --- Main Application Logic ---
inventory = load_inventory_from_file(DATA_FILE)
while True:
print("\n--- PyInventory Main Menu ---")
print("1: Display Current Inventory")
print("2: Add a New Product")
print("3: Update a Product") # New option
print("4: Delete a Product") # New option
print("q: Quit")
choice = input("Please enter your choice (1, 2, 3, 4, or q): ")
if choice == '1':
display_inventory(inventory, CURRENCY)
elif choice == '2':
add_product(inventory, CURRENCY)
elif choice == '3': # New block
update_product(inventory, CURRENCY)
elif choice == '4': # New block
delete_product(inventory)
elif choice.lower() == 'q':
save_inventory_to_file(inventory, DATA_FILE)
print("Inventory saved. Exiting PyInventory. Goodbye!")
break
else:
print("Invalid choice. Please try again.")
The full, final code for this chapter is available below. You can run it and test your new powers to update quantities and prices, and to remove products entirely.
The Complete main.py
for Chapter 8
# --- PyInventory: A Step-by-Step Journey to Profit ---
# Chapter 8: Full Control: Updating and Deleting Inventory
import json
# --- Configuration ---
CURRENCY = "MAD"
DATA_FILE = "inventory.json"
# --- Function Definitions ---
def save_inventory_to_file(inventory_list, filename):
with open(filename, 'w') as file:
json.dump(inventory_list, file, indent=4)
def load_inventory_from_file(filename):
try:
with open(filename, 'r') as file:
return json.load(file)
except FileNotFoundError:
return []
def find_product(inventory_list):
"""Helper function to find a product by name and return its index and data."""
search_name = input("Enter the name of the product to find: ")
for index, product in enumerate(inventory_list):
if product['name'].lower() == search_name.lower():
return index, product
return None, None
def display_inventory(inventory_list, currency_symbol):
print("\n--- Current Inventory Report ---")
print("-" * 60)
total_inventory_value = 0.0
if not inventory_list:
print("Inventory is currently empty.")
else:
print(f"{'Product':<30} | {'Quantity':<10} | {'Value':>15}")
print("-" * 60)
for item in inventory_list:
item_value = item['quantity'] * item['price']
total_inventory_value += item_value
print(f"{item['name']:<30} | {item['quantity']:<10} | {currency_symbol}{item_value:>14.2f}")
print("-" * 60)
print(f"GRAND TOTAL INVENTORY VALUE: {currency_symbol}{total_inventory_value:>40.2f}")
print("-" * 60)
def add_product(inventory_list, currency_symbol):
print("\n--- Add a New Product ---")
product_name = input("Enter the new product name: ")
quantity_str = input(f"Enter the quantity for {product_name}: ")
price_str = input(f"Enter the price per item (in {currency_symbol}): ")
new_product = {"name": product_name, "quantity": int(quantity_str), "price": float(price_str)}
inventory_list.append(new_product)
print(f"\nSUCCESS: '{product_name}' has been added to the inventory.")
def update_product(inventory_list, currency_symbol):
"""Finds a product and allows the user to update its details."""
index, product = find_product(inventory_list)
if product is None:
print("Product not found.")
return
print(f"Found: {product['name']}. Current quantity: {product['quantity']}, Current price: {currency_symbol}{product['price']}")
new_quantity_str = input(f"Enter new quantity (or press Enter to keep {product['quantity']}): ")
new_price_str = input(f"Enter new price (or press Enter to keep {product['price']}): ")
if new_quantity_str:
product['quantity'] = int(new_quantity_str)
if new_price_str:
product['price'] = float(new_price_str)
print(f"SUCCESS: '{product['name']}' has been updated.")
def delete_product(inventory_list):
"""Finds and deletes a product from the inventory."""
index, product = find_product(inventory_list)
if product is None:
print("Product not found.")
return
product_name = product['name']
inventory_list.pop(index)
print(f"SUCCESS: '{product_name}' has been deleted from the inventory.")
# --- Main Application Logic ---
inventory = load_inventory_from_file(DATA_FILE)
while True:
print("\n--- PyInventory Main Menu ---")
print("1: Display Current Inventory")
print("2: Add a New Product")
print("3: Update a Product")
print("4: Delete a Product")
print("q: Quit")
choice = input("Please enter your choice (1, 2, 3, 4, or q): ")
if choice == '1':
display_inventory(inventory, CURRENCY)
elif choice == '2':
add_product(inventory, CURRENCY)
elif choice == '3':
update_product(inventory, CURRENCY)
elif choice == '4':
delete_product(inventory)
elif choice.lower() == 'q':
save_inventory_to_file(inventory, DATA_FILE)
print("Inventory saved. Exiting PyInventory. Goodbye!")
break
else:
print("Invalid choice. Please try again.")
Chapter 8: Summary & What's Next
You now have a fully functional CRUD application!
You learned about the four crucial CRUD operations.
You wrote a helper function to avoid repeating code.
You used
enumerate
to search a list efficiently.You implemented logic to update and delete inventory items.
Our command-line tool is now feature-complete. However, as applications grow, errors become more likely. What if the user enters "abc" for a product's price? Our program will crash. In the next chapter, we will make our program robust and professional by adding comprehensive error handling.