POST naar database
Nu combineren we formulieren met een database: data van een gebruiker permanent opslaan.
Voorbeeld: Naam opslaan
Formulier (static/pages/naam_opslaan.html):
<!DOCTYPE html>
<html>
<body>
<h1>Bewaar je naam</h1>
<form method="post" action="/opslaan">
<input type="text" name="naam" required>
<button type="submit">Opslaan</button>
</form>
</body>
</html>
Endpoints (main.py):
from fastapi import FastAPI, Form
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from sqlitedict import SqliteDict
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/naam")
async def naam_formulier():
return FileResponse("static/pages/naam_opslaan.html")
@app.post("/opslaan")
async def naam_opslaan(naam: str = Form(...)):
with SqliteDict("namen.db") as db:
db["laatste_naam"] = naam
db.commit()
return {"bericht": f"'{naam}' opgeslagen!"}
- Regel 13-14:
Het POST-endpoint uit Eigen POST request:
naamkomt uit het formulier. - Regel 15-17:
Nieuw is wat je ermee doet. Binnen het
with-blok open je de database, zet je de naam onder de sleutellaatste_naamen schrijf je hem weg metcommit(). Elke nieuwe naam overschrijft de vorige, want de sleutel is steeds dezelfde. - Regel 19:
Het antwoord komt ná het
with-blok: de database is dan al netjes gesloten.
Testen
- Ga naar
http://127.0.0.1:8000/naam - Vul een naam in en klik Opslaan
- Stop de server en start opnieuw
- De naam staat nog in
namen.db.
Data terug lezen
@app.get("/toon_naam")
async def toon_naam():
with SqliteDict("namen.db") as db:
naam = db.get("laatste_naam", "Nog niets opgeslagen")
return {"naam": naam}
- Regel 4:
db.get(sleutel, standaard)geeft de standaardwaarde terug als de sleutel nog niet bestaat, in plaats van te crashen. Zo werkt de pagina ook vóór de eerste keer opslaan.
Data niet opgeslagen? Check of je db.commit() niet vergeet. Bekijk de troubleshooting pagina voor meer oplossingen.
Opdrachten
Opdracht 1: Predict - Overschrijven
Je slaat eerst "Jan" op, dan "Sarah". Wat staat er in de database?
Tip
Beide worden opgeslagen onder dezelfde key ("laatste_naam"). Wat gebeurt er als je twee keer dezelfde key gebruikt?
Antwoord
Alleen "Sarah" — de nieuwe waarde overschrijft de oude bij dezelfde key.
Opdracht 2: Run
Maak het formulier en de endpoints uit het voorbeeld. Test of de naam echt bewaard blijft door de server te stoppen en opnieuw te starten.
Opdracht 3: Investigate - Dezelfde key
Wat als twee gebruikers allebei hun naam opslaan via het formulier? Blijven beide namen bewaard?
Antwoord
Nee. Beide namen worden opgeslagen onder "laatste_naam", dus de tweede overschrijft de eerste. Om meerdere namen op te slaan heb je unieke keys nodig, bijvoorbeeld met time.time_ns() (zie opdracht 5).
Opdracht 4: Make - Score opslaan
Maak een formulier met een number input voor een game score. Sla de score op in scores.db en maak een endpoint om de score te bekijken.
Tip
Gebruik <input type="number" name="score"> in je HTML en score: int = Form(...) in Python. Maak een apart GET endpoint dat db.get("score", 0) teruggeeft.
Antwoord
static/pages/score_form.html:
<!DOCTYPE html>
<html>
<body>
<h1>Game Score</h1>
<form method="post" action="/score">
<input type="number" name="score" required>
<button type="submit">Opslaan</button>
</form>
</body>
</html>
@app.get("/score")
async def score_form():
return FileResponse("static/pages/score_form.html")
@app.post("/score")
async def score_opslaan(score: int = Form(...)):
with SqliteDict("scores.db") as db:
db["score"] = score
db.commit()
return {"bericht": f"Score {score} opgeslagen!"}
@app.get("/toon_score")
async def toon_score():
with SqliteDict("scores.db") as db:
score = db.get("score", 0)
return {"score": score}
Opdracht 5: Make - Gastenboek
Maak een gastenboek met naam en bericht. Gebruik time.time_ns() als unieke key zodat berichten niet overschreven worden:
import time
key = f"bericht_{time.time_ns()}"
db[key] = {"naam": naam, "bericht": bericht}
Gebruik time.time_ns() (nanoseconden) en niet int(time.time()) (hele seconden). Twee berichten die binnen dezelfde seconde binnenkomen krijgen anders dezelfde sleutel, en dan overschrijft het tweede het eerste.
Tip
Je hebt twee <input> velden nodig (name="naam" en name="bericht"). Gebruik time.time_ns() om een unieke key te genereren, zodat elk bericht apart wordt opgeslagen.
Antwoord
static/pages/gastenboek_form.html:
<!DOCTYPE html>
<html>
<body>
<h1>Gastenboek</h1>
<form method="post" action="/gastenboek">
<input type="text" name="naam" placeholder="Je naam" required>
<input type="text" name="bericht" placeholder="Je bericht" required>
<button type="submit">Verstuur</button>
</form>
</body>
</html>
import time
@app.get("/gastenboek")
async def gastenboek_form():
return FileResponse("static/pages/gastenboek_form.html")
@app.post("/gastenboek")
async def gastenboek_opslaan(naam: str = Form(...), bericht: str = Form(...)):
with SqliteDict("gastenboek.db") as db:
key = f"bericht_{time.time_ns()}"
db[key] = {"naam": naam, "bericht": bericht}
db.commit()
return {"bericht": "Bedankt voor je bericht!"}
@app.get("/berichten")
async def berichten():
with SqliteDict("gastenboek.db") as db:
alle_berichten = list(db.values())
return {"berichten": alle_berichten}
Je berichten staan nu in de database, maar /berichten geeft ze nog als JSON terug. In Een lijst tonen zet je ze op een echte pagina.