Gegevens opslaan met SqliteDict
Hier bouw je op verder: Dictionaries en Een bestand openen met with
Weet je dit niet meer zeker? Lees het terug voordat je verdergaat.
- Python Dictionaries
- Python Een bestand openen met with
Tot nu toe verdwijnt alle data als je programma stopt. Met sqlitedict bewaar je hem in een bestand, en daar staat hij de volgende keer nog. Je oefent er eerst mee in een los script, zonder server. Pas in Een formulier opslaan zet je het in je main.py.
Wat je in deze les en de vijf lessen hierna leert, staat ook kort op een rij in de naslag SqliteDict.
Installatie
Je server houdt de terminal in VS Code bezet: wat je daar nu typt, komt niet aan. Stop hem eerst met Ctrl+C. De commando's op deze pagina typ je daarna in dezelfde terminal. De server heb je pas weer nodig in Een formulier opslaan, en dan start je hem met fastapi dev main.py.
python -m pip install sqlitedict
Data opslaan
Maak test_db.py, naast je main.py:
from sqlitedict import SqliteDict
with SqliteDict("mijn_data.db") as db:
db["naam"] = "Jan"
db["leeftijd"] = 16
db.commit()
print("Data opgeslagen")
- Regel 3:
withopent de database uit het bestandmijn_data.dben sluit hem vanzelf weer na het ingesprongen blok. Bestaat het bestand nog niet, dan maakt SqliteDict het aan. - Regel 4-5:
Binnen het blok gedraagt
dbzich als een dictionary: een sleutel, een waarde. - Regel 6:
db.commit()schrijft de wijzigingen echt naar het bestand. Zonder deze regel is de wijziging weg zodra hetwith-blok sluit, ook als je programma daarna nog doorloopt.
Draai python test_db.py en kijk of je voorspelling klopte.
Data uitlezen
Een tweede script leest uit wat het eerste opsloeg. Maak lees_db.py:
from sqlitedict import SqliteDict
with SqliteDict("mijn_data.db") as db:
print(db["naam"])
print(db["leeftijd"])
Draai python lees_db.py:
Jan
16
lees_db.py heeft nooit iets opgeslagen. De naam en de leeftijd komen uit het bestand dat test_db.py schreef, en ze staan er ook nog als je VS Code afsluit en morgen weer opent.
Waarom is db.commit() nodig?
Een database slaat wijzigingen niet meteen op in het bestand. Met db.commit() zeg je: "Sla nu alles echt op." Vergeet je dat, dan verdwijnen je wijzigingen zodra de database sluit, aan het eind van het with-blok. Vergelijk het met een Word-document: je moet op "Opslaan" klikken, anders ben je je werk kwijt.
Test jezelf met een script dat na commit() nog iets verandert:
from sqlitedict import SqliteDict
with SqliteDict("proef.db") as db:
db["naam"] = "Piet"
db.commit()
db["naam"] = "Sara"
Er gaat iets mis
Je wijziging komt niet aan
Je verandert in test_db.py de naam in "Sara" en draait het. Daarna geeft lees_db.py nog steeds:
Jan
16
Oorzaak: de regel db.commit() ontbreekt, of staat buiten het with-blok. SqliteDict gooit de wijziging dan weg zodra het blok sluit, zonder foutmelding. Wat je eerder wél opsloeg, staat er nog.
Oplossing: zet db.commit() binnen het with-blok, onder de laatste wijziging.
from sqlitedict import SqliteDict
# FOUT: commit staat na het with-blok, en dan is de database al dicht
with SqliteDict("mijn_data.db") as db:
db["naam"] = "Sara"
db.commit()
# GOED
with SqliteDict("mijn_data.db") as db:
db["naam"] = "Sara"
db.commit()
KeyError, terwijl je het net hebt opgeslagen
lees_db.py stopt met:
KeyError: 'naam'
Oorzaak: het script draait in een andere map dan test_db.py. SqliteDict("mijn_data.db") zoekt het bestand in de map waarin je terminal staat, niet per se naast je script. Bestaat het daar niet, dan maakt SqliteDict stil een nieuwe, lege database aan, en daarin staat geen naam. Kijk maar: in die andere map staat nu een tweede mijn_data.db.
Oplossing: start je scripts vanuit de terminal in je projectmap, de map met main.py. Gooi de lege mijn_data.db in de andere map weg.
KeyError door één letter
KeyError: 'Naam'
Oorzaak: een sleutel moet letter voor letter gelijk zijn, hoofdletters meegeteld. Je sloeg op onder "naam" en vraagt om "Naam".
Oplossing: schrijf de sleutel bij het uitlezen precies zoals bij het opslaan. Wil je zien welke sleutels er echt in staan, dan helpt het script uit Alles bekijken: len en items.
Opdrachten
Opdracht 1: Predict - Wat gebeurt er?
from sqlitedict import SqliteDict
with SqliteDict("test.db") as db:
db["score"] = 100
db.commit()
with SqliteDict("test.db") as db:
print(db["score"])
Opdracht 2: Run - Een tweede keer opslaan
Verander in test_db.py de leeftijd in 17 en draai het nog een keer. Wat geeft lees_db.py nu: twee leeftijden, of één?
Antwoord
Eén: 17. Onder elke sleutel staat één waarde, net als in een dictionary. Een nieuwe waarde onder dezelfde sleutel overschrijft de oude. Zet de leeftijd daarna terug op 16 en draai test_db.py nog een keer: de lessen hierna gaan uit van Jan en 16.
Opdracht 3: Investigate - Commit vergeten
Zet in test_db.py een # voor de regel db.commit(), verander de naam in "Piet" en draai het. Welke naam geeft lees_db.py? Zet daarna de # weer weg en de naam terug op "Jan", en draai test_db.py nog een keer.
Antwoord
De naam van de vorige keer, Jan. Zonder commit() komt Piet nooit in het bestand: zodra het with-blok sluit, is de wijziging weg. Open je de database daarna opnieuw, ook in hetzelfde programma, dan staat hij er niet in.
Opdracht 4: Modify - Een sleutel erbij
Sla in test_db.py ook je woonplaats op, onder de sleutel "woonplaats", en laat lees_db.py hem printen.
Tip
Eén regel erbij in test_db.py, boven db.commit(), en één print erbij in lees_db.py. Draai eerst test_db.py, dan pas lees_db.py.
Antwoord
In test_db.py:
from sqlitedict import SqliteDict
with SqliteDict("mijn_data.db") as db:
db["naam"] = "Jan"
db["leeftijd"] = 16
db["woonplaats"] = "Utrecht"
db.commit()
print("Data opgeslagen")
In lees_db.py komt print(db["woonplaats"]) onder de andere twee. Draai je lees_db.py vóór test_db.py, dan krijg je KeyError: 'woonplaats': de sleutel staat er dan nog niet in.
Opdracht 5: Make - Favorieten opslaan
Maak een programma dat drie favorieten opslaat (eten, muziek, game) in favorieten.db, en een tweede programma dat ze uitleest.
Tip
Gebruik drie sleutels: db["eten"], db["muziek"], db["game"]. Sla alles op met één db.commit() aan het eind.
Antwoord
favorieten_opslaan.py:
from sqlitedict import SqliteDict
with SqliteDict("favorieten.db") as db:
db["eten"] = "pizza"
db["muziek"] = "pop"
db["game"] = "Minecraft"
db.commit()
favorieten_lezen.py:
from sqlitedict import SqliteDict
with SqliteDict("favorieten.db") as db:
print("Eten:", db["eten"])
print("Muziek:", db["muziek"])
print("Game:", db["game"])
Door naar Alles bekijken: len en items.