Ga naar hoofdinhoud

POST naar database

Hier bouw je op verder

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!"}
  1. Regel 13-14:

    Het POST-endpoint uit Eigen POST request: naam komt uit het formulier.

  2. Regel 15-17:

    Nieuw is wat je ermee doet. Binnen het with-blok open je de database, zet je de naam onder de sleutel laatste_naam en schrijf je hem weg met commit(). Elke nieuwe naam overschrijft de vorige, want de sleutel is steeds dezelfde.

  3. Regel 19:

    Het antwoord komt ná het with-blok: de database is dan al netjes gesloten.

Testen

  1. Ga naar http://127.0.0.1:8000/naam
  2. Vul een naam in en klik Opslaan
  3. Stop de server en start opnieuw
  4. 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}
  1. 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.

Gaat er iets mis?

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}
pas op

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.