Streamlit Shopping App

Project Description

So I’ve been toying with the idea of creating a shopping list application for a while now.

I wanted to create it in such a way that everybody in the family could contribute. We order all our food once a week, and then I go and collect it.

With the app, everybody would have a say in that week’s choice of dinners. This led to the conclusion that we would need a recipe section also for people to choose from or add to.

Here’s how the final app looks:

👉 Try It Yourself: Feel free to check out the live demo app here.

Install Dependencies

The first thing for us to do is install the PIP packages that are not built into Python itself. If you run the commands below in your terminal this should take care of it.

I’ll go into more detail on what each of these does as we encounter them.

pip install streamlit
pip install streamlit_option_menu
pip install isoweek
Pip install Deta

Step 1: Set Up the Directory Structure

I use VS Code as my editor of choice, and setting up a new project folder there is a breeze. Right-click in the Explorer menu on the left side and click New Folder. After that, we set up the folder structure as shown below.

├── .streamlit
│   ├── config.toml
│   └── secrets.toml
├── db.py
|── shopping_list.py

Make sure you don’t forget to add the ‘.’ in front of the .streamlit folder name. This folder will keep our configuration and secret files for the app to function.

The shopping_list.py is our main application file, while the db.py file will hold all the logic used for interacting with the Deta database.

Step 2: Import dependencies and Streamlit basic set-up

Our initial work will be done in the shopping_list.py file. At the top, we import everything we need.

#---PIP PACKAGES---#
import streamlit as st
from streamlit_option_menu import option_menu
from isoweek import Week


#---BUILT-IN PYTHON MODULES
from datetime import datetime, date
import calendar
import uuid


#---IMPORT THE DATABASE PYTHON FILE db.py---#
import db as db

The next step in the process is for us to create a basic Streamlit app that we can launch. Every time we change something in our code, we’ll see the effect this has after refreshing the browser window. 

#---STREAMLIT SETTINGS---#
page_title = "Weekly dinner and shopping app"
page_icon = ":pouch:"
layout = "centered"

In the #---STREAMLIT SETTINGS---# block, we define the variables to initialize the app. This makes it nice and tidy, plus it is easy to change if you decide later to tinker with them.

#---STREAMLIT PAGE CONFIG---#
st.set_page_config(page_title=page_title, page_icon=page_icon, layout=layout)
st.title(f"{page_title} {page_icon}")

We use the variables in the next block,  #---STREAMLIT PAGE CONFIG---#, to initialize the app. The st.set_page_config() function is always run at the beginning of a Streamlit app. If you don’t do this, Streamlit will throw an error.

#---STREAMLIT CONFIG HIDE---#
hide_st_style = """<style>
                #MainMenu {visibility : hidden;}
                footer {visibility : hidden;}
                header {visibility : hidden;}
                </style>
                """
st.markdown(hide_st_style, unsafe_allow_html=True)

The last block, #---STREAMLIT CONFIG HIDE---#, is optional but hides the “Made with Streamlit” banner at the bottom and the hamburger menu at the top if you want to.

If you now run the command below in the root of your project folder, a browser window should open for you. If everything went well you should see the page title at the top of an otherwise empty page.

streamlit run shopping_list.py

Step 3: Creating the variables

For the app to work, I used multiple dictionaries. We’ll be creating those next. To save you a lot of typing 🙂, I’ll insert all of the code below, and you can just copy and paste it.

#---DICT INIT---#
shopping_list = {
    "fruit_and_veg" : {"title" : "Fruit and Veggies", "items" : []},
    "meat_and_fish" : {"title" :"Fresh meat and fish", "items" : []},
    "housekeeping" : {"title" :"Housekeeping supplies", "items" : []},
    "carbs" : {"title" : "Potatoes, rice, pasta, etc", "items" : []},
    "snacks" : {"title" : "Snacks", "items" : []},
    "dairy" : {"title" : "Dairy", "items" : []},
    "personal_care" : {"title" : "Personal care", "items" : []},
    "pets" : {"title" : "Pets", "items" : []},
    "beverages" : {"title" : "Beverages", "items" : []},
    "spices_and_cond" : {"title" : "Spices and condiments", "items" : []},
    "frozen" : {"title" : "Frozen", "items" : []}
    }


key_dict = {
    'fruit_and_veg': [],
    'meat_and_fish': [],
    'housekeeping': [],
    'carbs': [],
    'snacks': [],
    'dairy': [],
    'personal_care': [],
    'pets': [],
    'beverages': [],
    'spices_and_cond': [],
    'frozen': []
    }
ingredients_dict = {}


instructions_dict = {}

We’ll also need another set of variables to keep track of the current week and get its week number. Luckily the datetime, calendar, and isoweek modules have us covered!

#---PERIOD VALUES---#
year = datetime.today().year
month = datetime.today().month
day = datetime.today().day+4
months = list(calendar.month_name[1:])
week_number = date(year, month, day).isocalendar()[1]
week = Week(year, week_number)
week_plus1 = Week(year, week_number+1)

Step 4: Setting up Deta Base

For our database, we’ll be using an awesome service called Deta. They offer free Cloud computing units, NoSQL databases, and a file storage service. Setting up an account only takes a minute, and afterward, you are ready to start.

The first thing we need to do is set up an API key so we can set up the connection between our application and Deta. Click the “Project Keys” on the left side and then “Create Key”. Make sure to save it somewhere, as you will need it shortly. 

Step 5: Storing the API Key securely

The next step is creating the functionality that will allow us to interact with the database itself. For that to work, we need to set up the connection to the database first. For this, we will be using the Streamlit Secrets module. This allows us to securely store the key and call it when we need it later.

Navigate to the secrets.toml file situated in the .streamlit folder. Once there you create a DETA_KEY variable and assign the API Key you saved earlier to it. Don’t forget to add quotation marks around it!

DETA_KEY = "<DETA API KEY>"

Step 6: Building out the database functions for the shopping list

With all the preparatory work done, we can start on the good stuff! The first order of business is opening the empty db.py file and importing everything we need to get this to work.

from deta import Deta
from pprint import pprint
import streamlit as st

The pprint module is not required but helps out a lot in printing out dictionaries in a readable way. This helps a lot, I can assure you 🙂.

After the import, we are ready to connect to the database. The code below will first retrieve the key from the secrets.toml file and assign it to the variable DETA_KEY. Next, it will use that variable to create a Deta object.

DETA_KEY = st.secrets.DETA_KEY
deta = Deta(DETA_KEY)

Once this is done, it takes only two lines of code to create the two Bases (Deta’s equivalent of tables or collections) I use in this project. 

sl = deta.Base("sl")
recipes = deta.Base("recipes")
<