Loading Data from the Database#
In this tutorial, you will learn how to create a data model and synchronize it with a database. You can use this for many purposes — for example, storing quiz questions and answers, high scores, game state loading, and more.
Step 1: Creating the Model#
Start by creating a model for your data in a new file — just as you would store it in Python.
For example, a high score could be represented as a simple list storing names and scores:
[(Andreas, 100), (Martin, 200), (Julius, 50)]
Order doesn’t matter yet, because you can always sort the list later.
Your class might initially look like this:
File: highscore_model.py
import sqlite3
class Highscore:
def __init__(self, scores=[]):
self.scores: list = scores
The class has an attribute scores
, which is either passed as a parameter or defaults to an empty list.
Setting Up the Database#
Use the tool DB Browser for SQLite to set up your database.
Create a table with three fields: Name, Score, and ID.
Add sample data to the database so you can test reading from it later.
Reading from the Database#
Next, implement a method to load the data.
Add this method to your class:
@classmethod
def from_db(cls):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = 'SELECT Name, Score FROM Highscore'
cursor.execute(sql)
rows = cursor.fetchall()
connection.close()
return cls(rows)
This is a classmethod
, used like a factory to create a Highscore
object from the database.
A connection to the database is opened, a SQL query is run via a cursor, and the results are fetched and returned.
To test it:
hs = Highscore.from_db()
print(hs.scores)
Writing to the Database#
Add the following method to write to the database:
def create(self, name, score):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = f"INSERT INTO Highscore (Name, Score) VALUES ('{name}', '{score}')"
cursor.execute(sql)
connection.commit()
connection.close()
self.scores.append((name, score))
This creates a new record both in the database and in the local data structure.
CRUD Operations#
CRUD stands for:
Create – Add a record
Read – Read records
Update – Update existing records
Delete – Remove records
You need to think about these when interacting with databases.
Create#
Implemented in the create
method.
Read#
Handled by from_db
.
Update#
To update an existing entry:
def update(self, score_id, name, new_score):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = f"UPDATE Highscore SET Name = '{name}', Score = '{new_score}' WHERE ID='{score_id}'"
cursor.execute(sql)
connection.commit()
connection.close()
for score in self.scores:
if score[0] == score_id:
self.scores.remove(score)
self.scores.append((score_id, name, new_score))
Delete#
To delete an entry:
def delete(self, score_id):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = f"DELETE FROM Highscore WHERE ID='{score_id}'"
cursor.execute(sql)
connection.commit()
connection.close()
for score in self.scores:
if score[0] == score_id:
self.scores.remove(score)
Complete Code#
import sqlite3
class Highscore:
def __init__(self, scores=[]):
self.scores: list = scores
@classmethod
def from_db(cls):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = 'SELECT ID, Name, Score FROM Highscore'
cursor.execute(sql)
rows = cursor.fetchall()
connection.close()
return cls(rows)
def create(self, name, score):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = f"INSERT INTO Highscore (Name, Score) VALUES ('{name}', '{score}')"
cursor.execute(sql)
connection.commit()
connection.close()
self.scores.append((name, score))
def update(self, score_id, name, new_score):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = f"UPDATE Highscore SET Name = '{name}', Score = '{new_score}' WHERE ID='{score_id}'"
cursor.execute(sql)
connection.commit()
connection.close()
for score in self.scores:
if score[0] == score_id:
self.scores.remove(score)
self.scores.append((score_id, name, new_score))
def delete(self, score_id):
connection = sqlite3.connect("highscore_db.db")
cursor = connection.cursor()
sql = f"DELETE FROM Highscore WHERE ID='{score_id}'"
cursor.execute(sql)
connection.commit()
connection.close()
for score in self.scores:
if score[0] == score_id:
self.scores.remove(score)
hs = Highscore.from_db()
# hs.create("Max Meier", 200)
hs.update(2, "Max Meier2", 200)
hs.delete(2)
print(hs.scores)
Integrating the Model into Your Game#
Once you’ve written your model, you can use it in your main program.
Here’s a sample game where the player avoids falling balls. Once hit, the game ends. Initially, it looks like this:
from miniworlds import *
import random
import highscore_model
import easygui
world = World(200, 600)
enemies = []
player = Circle(100, 500)
player.radius = 20
my_score = 0
score_actor = Number(10, 10)
@player.register
def on_key_pressed_a(self):
self.move_left()
@player.register
def on_key_pressed_d(self):
self.move_right()
@player.register
def on_detecting_right_border(self):
self.move_back()
@player.register
def on_detecting_left_border(self):
self.move_back()
def create_enemy():
enemy = Circle(random.randint(20, 180), 50)
enemy.radius = random.randint(10, 30)
enemies.append(enemy)
@world.register
def act(self):
global my_score
if self.frame % 100 == 0:
create_enemy()
for enemy in enemies:
enemy.move_down()
if "bottom" in enemy.detect_borders():
enemies.remove(enemy)
enemy.remove()
my_score += 1
score_actor.set_number(my_score)
To add a game over and display the high score:
@world.register
def act(self):
global my_score
if self.frame % 100 == 0:
create_enemy()
for enemy in enemies:
enemy.move_down()
if "bottom" in enemy.detect_borders():
enemies.remove(enemy)
enemy.remove()
my_score += 1
score_actor.set_number(my_score)
if enemy in player.detect_actors():
world.reset()
name = easygui.enterbox(f"You reached {my_score} points! Enter your name", "Highscore")
new_highscore(name, my_score)
new_highscore
is defined as:
def new_highscore(name, points):
highscore = highscore_model.Highscore.from_db()
highscore.create(name, points)
scores = highscore.from_db().scores
scores.sort()
for index, ranking in enumerate(scores[0:10]):
t = Text((20, index * 40))
t.text = f"{ranking[0]} - Points: {ranking[1]}"
t.font_size = 10
This fetches, updates, and displays the top 10 scores.