Kap 4.6
Miniuppgift: Använda SQLite-databaser
Bygg ett bibliotekssystem med databas, moduler, sökning och felhantering.
Mål
Efter miniuppgiften ska du kunna...
- skapa en SQLite-databas och tabell
- lägga till, söka och visa poster
- dela upp programmet i moduler
- validera användarens inmatning
- hantera SQLite-fel med
try/except/finally
Du kombinerar
Tidigare kapitel används tillsammans
- Kap 3.7: egna moduler och import.
- Kap 4.2: undantagshantering.
- Kap 4.3: tydlig kodstruktur.
- Kap 4.5: SQLite och SQL.
Filstruktur
Två Pythonfiler och en databasfil
bibliotekssystem/
├── main.py
├── databas.py
└── bibliotek.db
bibliotek.db skapas när programmet körs.
Ansvar
Varje fil har en uppgift
main.py
Visar menyn, läser indata och anropar funktioner.
databas.py
Öppnar databasen och kör SQL.
bibliotek.db
Sparar böckerna permanent.
Programflöde
Från menyval till databas
main.pyläser användarens val.- En funktion i
databas.pyanropas. - Funktionen ansluter till
bibliotek.db. - SQL körs mot tabellen
bocker. - Resultatet skrivs ut och anslutningen stängs.
Tabellen
bocker
id | titel | forfattare
1 | Bröderna Lejonhjärta | Astrid Lindgren
2 | Utvandrarna | Vilhelm Moberg
idär unikt och skapas automatiskt.titelmåste ha ett värde.forfattaremåste ha ett värde.
databas.py
Import och databasnamn
import sqlite3
DB_FIL = "bibliotek.db"
sqlite3 ger tillgång till SQLite.
DB_FIL används av alla databasfunktioner.
Skapa databas
SQL-kommandot
CREATE TABLE IF NOT EXISTS bocker (
id INTEGER PRIMARY KEY AUTOINCREMENT,
titel TEXT NOT NULL,
forfattare TEXT NOT NULL
)
Tabellen skapas bara om den inte redan finns.
Skapa databas
Hela funktionen
def skapa_databas():
conn = None
try:
conn = sqlite3.connect(DB_FIL)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS bocker (
id INTEGER PRIMARY KEY AUTOINCREMENT,
titel TEXT NOT NULL,
forfattare TEXT NOT NULL
)
""")
conn.commit()
except sqlite3.Error as e:
print("Fel vid skapande av databas:", e)
finally:
if conn:
conn.close()
conn = None
Varför skapas variabeln först?
conn = None
try:
conn = sqlite3.connect(DB_FIL)
finally:
if conn:
conn.close()
Om anslutningen misslyckas finns variabeln ändå.
if conn stänger bara en anslutning som faktiskt öppnades.
Validering
Stoppa tom titel och författare
if not titel.strip() or not forfattare.strip():
print("Titel och författare måste fyllas i.")
return
strip() tar bort mellanslag i början och slutet.
Även text som bara består av blanksteg stoppas.
Lägg till bok
INSERT INTO
cursor.execute(
"INSERT INTO bocker (titel, forfattare) VALUES (?, ?)",
(titel.strip(), forfattare.strip())
)
conn.commit()
Värdena skickas separat från SQL-frågan.
commit() sparar boken i databasfilen.
Lägg till bok
Hela strukturen
def lagg_till_bok(titel, forfattare):
if not titel.strip() or not forfattare.strip():
print("Titel och författare måste fyllas i.")
return
conn = None
try:
conn = sqlite3.connect(DB_FIL)
cursor = conn.cursor()
cursor.execute(
"INSERT INTO bocker (titel, forfattare) VALUES (?, ?)",
(titel.strip(), forfattare.strip())
)
conn.commit()
print("Bok tillagd!")
except sqlite3.Error as e:
print("Kunde inte lägga till bok:", e)
finally:
if conn:
conn.close()
Sökning
Stoppa ett tomt sökord
nyckelord = nyckelord.strip()
if not nyckelord:
print("Skriv ett sökord.")
return
Ett tomt sökord skulle annars skapa mönstret %%.
%% matchar alla rader.
LIKE
Sök i titel eller författare
cursor.execute(
"SELECT * FROM bocker "
"WHERE titel LIKE ? OR forfattare LIKE ?",
("%" + nyckelord + "%", "%" + nyckelord + "%")
)
% betyder valfri text före eller efter sökordet.
Sökexempel
Vad matchar mönstret?
nyckelord = "Lindgren"
mönster = "%Lindgren%"
1. Bröderna Lejonhjärta - Astrid Lindgren
Samma fråga söker i både titel och forfattare.
Sökresultat
Visa träffar eller ett meddelande
resultat = cursor.fetchall()
for bok in resultat:
print(f"{bok[0]}. {bok[1]} - {bok[2]}")
if not resultat:
print("Inga träffar.")
Visa alla
Hämta hela tabellen
cursor.execute("SELECT * FROM bocker")
resultat = cursor.fetchall()
for bok in resultat:
print(f"{bok[0]}. {bok[1]} - {bok[2]}")
if not resultat:
print("Inga böcker finns än.")
Specifikt fel
Varför sqlite3.Error?
except sqlite3.Error as e:
print("Sökning misslyckades:", e)
sqlite3.Error fångar fel från SQLite-biblioteket.
Exception skulle även fånga många fel som inte hör till databasen.
Det specifika undantaget gör avsikten tydligare.
finally
Anslutningen ska alltid stängas
finally:
if conn:
conn.close()
finally körs både när koden lyckas och när ett fel uppstår.
Databasanslutningen lämnas därför inte öppen.
main.py
Importera databasmodulen
import databas
def main():
databas.skapa_databas()
Databasen och tabellen skapas innan menyn börjar användas.
Modulnamnet visar att funktionen kommer från databas.py.
Meny
Fyra alternativ
def visa_meny():
print("\nMeny:")
print("1. Lägg till bok")
print("2. Sök bok")
print("3. Visa alla böcker")
print("4. Avsluta")
Menyval
Anropa rätt databasfunktion
if val == "1":
titel = input("Titel: ")
forfattare = input("Författare: ")
databas.lagg_till_bok(titel, forfattare)
elif val == "2":
nyckelord = input("Sökord: ")
databas.sok_bok(nyckelord)
elif val == "3":
databas.visa_alla_bocker()
elif val == "4":
break
else:
print("Ogiltigt val.")
Hela samarbetet
Vem gör vad?
main.py
Tar emot titel och författare.
databas.lagg_till_bok(...)
Validerar och kör INSERT INTO.
bibliotek.db
Sparar boken i tabellen bocker.
Återanvändning
Varför två filer?
main.pykan ändras utan att SQL-koden flyttas.databas.pykan testas separat.- Ett framtida grafiskt gränssnitt kan återanvända databasmodulen.
- Varje fil blir kortare och har ett tydligare ansvar.
Testfall
Testa mer än normalfallet
- Starta programmet och kontrollera att databasen skapas.
- Lägg till flera böcker.
- Försök lägga till en tom titel.
- Sök på en del av en titel.
- Sök på en författare.
- Testa ett sökord utan träffar och ett tomt sökord.
Permanent data
Testa flera körningar
- Lägg till böcker.
- Avsluta programmet.
- Starta programmet igen.
- Välj Visa alla böcker.
Böckerna ska finnas kvar i bibliotek.db.
VS Code
Inspektera databasen visuellt
Installera SQLite Viewer av Florian Klampfer.
Öppna sedan bibliotek.db i VS Code.
Du kan se tabellen bocker, kolumnerna och de sparade raderna.
Tillägget är valfritt; Pythonprogrammet fungerar utan det.
Sammanfattning
Miniuppgiften kombinerar...
- SQLite-tabell och SQL-frågor
- platshållare och
LIKE-sökning - validering med
strip() sqlite3.Errorochfinally- moduler med separata ansvarsområden
- meny, testfall och permanent lagring