Ga naar hoofdinhoud

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.

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")
  1. Regel 3:

    with opent de database uit het bestand mijn_data.db en sluit hem vanzelf weer na het ingesprongen blok. Bestaat het bestand nog niet, dan maakt SqliteDict het aan.

  2. Regel 4-5:

    Binnen het blok gedraagt db zich als een dictionary: een sleutel, een waarde.

  3. Regel 6:

    db.commit() schrijft de wijzigingen echt naar het bestand. Zonder deze regel is de wijziging weg zodra het with-blok sluit, ook als je programma daarna nog doorloopt.

Voorspel
Je draait python test_db.py. Wat zie je in de terminal, en wat verandert er in je map?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

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"
Controlevraag
Het bestand proef.db bestaat nog niet. Je draait dit script. Wat staat er daarna onder de sleutel naam in proef.db?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

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"])
Voorspel
Wat print dit?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

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.