# Using Python lists as a database
For the first iteration of our application, we're going to store things inside a Python list instead of a database table.
When you think about it, lists and database tables are similar: they are both used to store individual things.
Inside a database table, we store rows of data. Each row has multiple pieces of data (one per column). Inside a list, we can store anything we like--including dictionaries. Each dictionary can contain multiple pieces of data as well.
This sample dictionary shows what the data storage will look like:
entries = [
{"content": "Today I started learning programing.", "date": "01-01-2020"},
{"content": "I created my first SQLite database!", "date": "02-01-2020"},
{"content": "I finished writing my programming diary application.", "date": "03-01-2020"},
{"content": "Today I'm going to continue learning programming!", "date": "04-01-2020"},
]
Each dictionary inside our entries
list will have two keys: "content"
and "date"
. Later on, when we use a database instead, the table will have two columns: content
and date
.
# Creating a database file
Let's get started by creating a Python file to contain the logic that interacts with the data store. For now the data store is a list, but later on it'll be a database.
I'll call this new file database.py
. The file structure in the project is now as follows:
- progdiary/
| - app.py
| - database.py
In this file I'll create the initial structure of our code. I like to this to plan out what functions and variables I'll need:
entries = []
def add_entry():
pass
def view_entries():
pass
TIP
The keyword pass
in Python means "do nothing". It's necessary because Python expects there to be an indented block under a function definition, so we at least need one line of code there.
# Add entries to the data store
Let's start by coding our add_entry
function. This function will ask the user for the entry content and date, and add them to the data store:
def add_entry():
entry_content = input("What have you learned today? ")
entry_date = input("Enter the date: ")
entries.append({"content": entry_content, "date": entry_date})
Simple as that!
# View entries in the data store
In our view_entries
function, we'll access the data store and print out each element for the users to read:
def view_entries():
for entry in entries:
print(f"{entry['date']}\n{entry['content']}\n\n")
When we do this, our application is almost complete!
# Using the database in app.py
At the moment our app.py
file contains all the application logic, but it does not make use of the data store. It looks like this:
menu = """Please select one of the following options:
1) Add new entry for today.
2) View entries.
3) Exit.
Your selection: """
welcome = "Welcome to the programming diary!"
print(welcome)
while (user_input := input(menu)) != "3":
if user_input == "1":
print("Adding...")
elif user_input == "2":
print("Viewing...")
else:
print("Invalid option, please try again!")
We need to use the data store instead of print "Adding..."
or "Viewing..."
. To do so, first we have to import our database functions. At the very top of the file I'm doing this:
from database import add_entry, view_entries
...
Now inside our loop, we'll just call the functions instead of printing:
from database import add_entry, view_entries
menu = """Please select one of the following options:
1) Add new entry for today.
2) View entries.
3) Exit.
Your selection: """
welcome = "Welcome to the programming diary!"
print(welcome)
while (user_input := input(menu)) != "3":
if user_input == "1":
add_entry()
elif user_input == "2":
view_entries()
else:
print("Invalid option, please try again!")
# Decoupling data from display
There is a glaring problem in the way we've structured our application:
The database.py
file does more than just interact with the database.
In fact, it does two things it shouldn't:
- Asks the user for input.
- Prints things out to the console.
We can hardly call the file "database" if it's also interacting with the user! So let's change that and move the user interaction to app.py
, and the database interact to database.py
.
I'll modify the database.py
functions so they take arguments or return values instead of interacting with the user. I'll also rename one of the functions:
entries = []
def add_entry(entry_content, entry_date):
entries.append({"content": entry_content, "date": entry_date})
def get_entries():
return entries
And then we'll modify app.py
so that it does the user interaction only:
while (user_input := input(menu)) != "3":
if user_input == "1":
entry_content = input("What have you learned today? ")
entry_date = input("Enter the date: ")
add_entry(entry_content, entry_date)
elif user_input == "2":
for entry in get_entries():
print(f"{entry['date']}\n{entry['content']}\n\n")
else:
print("Invalid option, please try again!")
Although this makes app.py
more complicated, it makes the whole application simpler. Now upon reading app.py
we can have a clear idea of what database.py
is doing: adding and getting entries from a data store. We've also made it clearer exactly what data we're adding to the database. Previously that was hidden inside database.py
.
We could improve the code inside app.py
further by splitting it into functions:
def prompt_new_entry():
entry_content = input("What have you learned today? ")
entry_date = input("Enter the date: ")
add_entry(entry_content, entry_date)
def view_entries(entries):
for entry in entries:
print(f"{entry['date']}\n{entry['content']}\n\n")
print(welcome)
while (user_input := input(menu)) != "3":
if user_input == "1":
prompt_new_entry()
elif user_input == "2":
view_entries(get_entries())
else:
print("Invalid option, please try again!")
Here the code is made longer, but the loop now is much easier to read. The function names are self-explanatory, and the code inside them is short and to the point.
Enjoyed this article?
You'll love the complete video course!
- Complete video lessons for each topic
- Get the most out of your learning
- Master Advanced PostgreSQL
- Get one-on-one help from a real person