In this activity, we will learn how to set up SQLite in Python and create a connection to a database. This is the first step in working with databases in Python, allowing us to store and retrieve data efficiently. SQLite comes pre-installed with Python, so there's no need to pip install anything extra.
Accept the GitHub Classroom invite
Open your Web Programming folder using VS Code
Clone the GitHub repository for this assignment.
E.g. git clone https://github.com/mullumhs/project-19-sqlite-your_username.git
cd into the project-19-sqlite folder in the VS Code terminal
Create an app.py using touch
import sqlite3
# Create a connection to a new database (or connect to an existing one)
conn = sqlite3.connect('movies.db')
# Create a cursor object
cursor = conn.cursor()
# Don't forget to close the connection when you're done!
conn.close()
We import the sqlite3 module, which comes built-in with Python.
sqlite3.connect() creates a new database file if it doesn't exist, or connects to it if it does.
The cursor object allows us to execute SQL commands.
It's important to close the connection when we're done to free up system resources.
Run this code and check your project directory. You should see a new file called movies.db.
Try changing the database name to something else, like my_movies.db.
What happens if you run the code multiple times?
In this activity, we will create a table in our SQLite database using Python. We'll recreate the movies table from our previous SQL lesson, demonstrating how to structure data in our database.
import sqlite3
conn = sqlite3.connect('movies.db')
cursor = conn.cursor()
# Create the movies table
cursor.execute('''
CREATE TABLE IF NOT EXISTS movies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
director TEXT,
year INTEGER,
rating FLOAT
)
''')
# Commit the changes and close the connection
conn.commit()
conn.close()
We use cursor.execute() to run SQL commands.
The SQL command is a multi-line string (''' ''') for better readability.
IF NOT EXISTS prevents errors if the table already exists.
AUTOINCREMENT for the id field ensures each new entry gets a unique identifier automatically.
conn.commit() saves the changes to the database.
Run this code. What happens if you run it multiple times?
Try adding a new column to the table, like genre TEXT.
Use a SQLite browser tool to open movies.db and verify that the table was created with the correct structure.
What happens if you try to create a table with a name that already exists?
In this activity, we will insert data into our movies table using Python. We'll demonstrate three methods of inserting data: inserting a single movie using string formatting (unsafe), inserting a single movie using a parameterized query (safe), and inserting multiple movies at once. This will show you how to populate your table with information efficiently and securely.
import sqlite3
conn = sqlite3.connect('movies.db')
cursor = conn.cursor()
# Insert a single movie using string formatting (UNSAFE - vulnerable to SQL injection)
movie = ('The Godfather', 'Francis Ford Coppola', 1972, 9.2)
cursor.execute(f'''
INSERT INTO movies (title, director, year, rating)
VALUES ('{movie[0]}', '{movie[1]}', {movie[2]}, {movie[3]})
''')
# Insert a single movie using a parameterized query (SAFE)
cursor.execute('''
INSERT INTO movies (title, director, year, rating)
VALUES (?, ?, ?, ?)
''', ('Pulp Fiction', 'Quentin Tarantino', 1994, 8.9))
# List of movies to insert
movies = [
('The Shawshank Redemption', 'Frank Darabont', 1994, 9.3),
('Inception', 'Christopher Nolan', 2010, 8.8),
('The Matrix', 'Lana and Lilly Wachowski', 1999, 8.7),
('Interstellar', 'Christopher Nolan', 2014, 8.6)
]
# Insert multiple movies
cursor.executemany('''
INSERT INTO movies (title, director, year, rating)
VALUES (?, ?, ?, ?)
''', movies)
# Commit the changes and close the connection
conn.commit()
conn.close()
The first insertion uses string formatting to construct the SQL query. This method is UNSAFE and vulnerable to SQL injection attacks.
The second insertion uses a parameterized query with ? placeholders. This is the SAFE method to prevent SQL injection.
For multiple insertions, we use cursor.executemany() with a list of tuples, which is also safe.
Parameterized queries separate the SQL command from the data, preventing malicious input from being executed as part of the SQL command.
conn.commit() is called after all insertions to save the changes to the database.
Run this code to insert the movies.
Modify the movies list to include some of your favorite movies.
Try inserting a movie with a missing value (e.g., no rating). What happens?
Use a SQLite browser to view the contents of your table. Are all the movies there?
In this activity, we will learn how to query our database and retrieve data using Python. We'll write several SELECT statements to fetch movie data, demonstrating how to extract and analyze information from our database.
import sqlite3
conn = sqlite3.connect('movies.db')
cursor = conn.cursor()
# Select all movies
cursor.execute('SELECT * FROM movies')
all_movies = cursor.fetchall()
print("All movies:")
for movie in all_movies:
print(movie)
# Select movies after 2000
cursor.execute('SELECT title, year FROM movies WHERE year > 2000')
recent_movies = cursor.fetchall()
print("\nMovies after 2000:")
for movie in recent_movies:
print(f"{movie[0]} ({movie[1]})")
# Select average rating
cursor.execute('SELECT AVG(rating) FROM movies')
avg_rating = cursor.fetchone()[0]
print(f"\nAverage rating: {avg_rating:.2f}")
conn.close()
cursor.execute() runs our SQL query.
cursor.fetchall() retrieves all rows from the result.
cursor.fetchone() retrieves a single row (useful for aggregate functions like AVG).
The results are returned as tuples (or a list of tuples for multiple rows).
We use formatted string literals (f-strings) to create more readable output.
Run this code and observe the output.
Modify the second query to find movies from a different year range.
Write a new query to find the highest rated movie.
Try to print the results in a different format (hint: you could use string formatting to align columns).
In this activity, we will learn how to update existing records and delete records from our database using Python. This demonstrates how to modify our data after it's been inserted.
import sqlite3
conn = sqlite3.connect('movies.db')
cursor = conn.cursor()
# Update the rating of a movie
cursor.execute('''
UPDATE movies
SET rating = 9.0
WHERE title = 'Inception'
''')
# Delete movies with rating less than 8.5
cursor.execute('DELETE FROM movies WHERE rating < 8.5')
# Let's see the results
cursor.execute('SELECT * FROM movies')
updated_movies = cursor.fetchall()
print("Updated movie list:")
for movie in updated_movies:
print(movie)
# Commit the changes and close the connection
conn.commit()
conn.close()
The UPDATE statement changes the rating of 'Inception' to 9.0.
The DELETE statement removes all movies with a rating less than 8.5.
After making changes, we select all movies to see the results.
Remember to commit changes that modify the database.
Run this code and observe how the movie list has changed.
Try updating a different movie's rating.
Experiment with different conditions in the DELETE statement.
What happens if you try to delete a movie that doesn't exist?
Now that you've learned the basics of SQLite in Python, it's time to put your skills to the test! Your challenge is to create a simple movie database manager program. Here's what it should do:
Create a movies.py file
Create a new SQLite database called my_movie_collection.db
Create a table called movies with columns for id, title, director, year, and rating
Implement functions to:
Add a new movie to the database
Display all movies
Update the rating of a movie
Delete a movie from the database
Find all movies by a specific director
Here's a code template for your Movie Database Manager. It already includes a working menu system and user input.
Your task is to fill in the body of each function with the appropriate SQLite operations:
import sqlite3
def create_connection():
# TODO: Create a connection to my_movie_collection.db
pass
def create_table(conn):
# TODO: Create the movies table
pass
def add_movie(conn, title, director, year, rating):
# TODO: Insert a new movie into the database
pass
def display_all_movies(conn):
# TODO: Select and display all movies
pass
def update_movie_rating(conn, title, new_rating):
# TODO: Update the rating of a specified movie
pass
def delete_movie(conn, title):
# TODO: Delete a specified movie from the database
pass
def find_movies_by_director(conn, director):
# TODO: Find and display all movies by a specific director
pass
def main():
conn = create_connection()
if conn is not None:
create_table(conn)
while True:
print("\n--- Movie Database Manager ---")
print("1. Add a new movie")
print("2. Display all movies")
print("3. Update a movie's rating")
print("4. Delete a movie")
print("5. Find movies by director")
print("6. Exit")
choice = input("Enter your choice (1-6): ")
if choice == '1':
title = input("Enter movie title: ")
director = input("Enter director name: ")
year = int(input("Enter release year: "))
rating = float(input("Enter rating (0-10): "))
add_movie(conn, title, director, year, rating)
print("Movie added successfully!")
elif choice == '2':
display_all_movies(conn)
elif choice == '3':
title = input("Enter movie title to update: ")
new_rating = float(input("Enter new rating (0-10): "))
update_movie_rating(conn, title, new_rating)
print("Rating updated successfully!")
elif choice == '4':
title = input("Enter movie title to delete: ")
delete_movie(conn, title)
print("Movie deleted successfully!")
elif choice == '5':
director = input("Enter director name: ")
find_movies_by_director(conn, director)
elif choice == '6':
print("Thank you for using Movie Database Manager. Goodbye!")
break
else:
print("Invalid choice. Please try again.")
conn.close()
else:
print("Error! Cannot create the database connection.")
if __name__ == '__main__':
main()
Implement each of the functions (create_connection(), create_table(), etc.) using the SQLite operations you learned in the lesson.
Run the program and use the menu to interact with your movie database.
Test each operation to ensure it works correctly.
In create_connection(), use sqlite3.connect() to create a connection to the database.
In create_table(), use CREATE TABLE IF NOT EXISTS to create the movies table.
For add_movie(), use an INSERT INTO statement.
In display_all_movies(), use a SELECT * query and fetch all results.
For update_movie_rating(), use an UPDATE statement with a WHERE clause.
In delete_movie(), use a DELETE statement with a WHERE clause.
For find_movies_by_director(), use a SELECT statement with a WHERE clause.
Remember to commit your changes after operations that modify the database, and to use parameterized queries to prevent SQL injection.
Remember to commit and push your code when done! Here are the terminal commands to do so:
Commit your changes with a meaningful message:
git commit -am "Your message here"
Note: The -a flag automatically stages all modified files before committing, -m is to add a message.
Push your changes to GitHub:
git push origin main