Invoer controleren: een keuze uit een lijst
Bij een getal zet je een onder- en een bovengrens, zoals in les 6. Bij een keuze uit een paar woorden, zoals een stemming, maak je een lijst met wat mag, en weiger je de rest.
Toestaan wat mag
STEMMINGEN = ["blij", "neutraal", "boos"]
@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(..., max_length=30),
bericht: str = Form(..., max_length=280),
cijfer: int = Form(..., ge=1, le=10),
stemming: str = Form(...),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
if stemming not in STEMMINGEN:
raise HTTPException(status_code=400, detail="Kies blij, neutraal of boos")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {
"naam": naam,
"bericht": bericht,
"cijfer": cijfer,
"stemming": stemming,
}
db.commit()
return {"lengte": len(bericht), "cijfer": cijfer, "stemming": stemming}
- Regel 1:
De lijst met wat mag, bovenaan
main.py, boven je endpoints. - Regel 12-13:
not inis waar als de stemming niet in de lijst staat. Dan stuur je een eigen400, net als bij de lege naam in les 5. - Regel 15-20:
De stemming gaat mee de database in, en komt terug in het antwoord. De dictionary staat over meer regels, want hij is te lang voor één.
Vervang bericht_plaatsen door deze, met je controle op het bericht als je die
hebt, en zet in static/formulier.html een <select> met dezelfde drie
woorden binnen het <form>:
<select name="stemming">
<option>blij</option>
<option>neutraal</option>
<option>boos</option>
</select>
Doe de test
Een script stemming.py probeert er twee:
import httpx
adres = "http://127.0.0.1:8000/bericht"
for stemming in ["blij", "vrolijk"]:
gegevens = {"naam": "Sara", "bericht": "hoi", "cijfer": "8", "stemming": stemming}
antwoord = httpx.post(adres, data=gegevens)
print(stemming, "->", antwoord.status_code, antwoord.json())
Je noemt op wat mag, dus alles wat je niet noemde, is geweigerd. Ook een woord dat je zelf nooit bedacht had.
Er gaat iets mis
Field required bij een script uit een eerdere les
cijfer.py print bij 8 nu 422 Field required.
Oorzaak: stemming is verplicht, net als cijfer. De scripts uit de
vorige lessen sturen geen stemming mee. In detail staat dan het veld
stemming met Field required.
Oplossing: zet in zo'n script "stemming": "blij" bij de data.
Het formulier geeft 422 met stemming
Elk bericht uit het formulier geeft 422 met stemming en Field required.
Oorzaak: het <select> staat buiten het <form>, of heet anders dan de
parameter.
Oplossing: controleer dat er name="stemming" staat, en dat het
<select> tussen <form> en </form> staat.
Opdrachten
Opdracht 1: Investigate - Een hoofdletter
Je stuurt als stemming Blij, met een hoofdletter.
Vraag: wat antwoordt de server, en hoe zorg je dat Blij toch mag?
Tip
"Blij" == "blij" is in Python niet waar. Met lower() maak je van alle
letters kleine letters.
Antwoord
400 {'detail': 'Kies blij, neutraal of boos'}. Blij staat niet in de lijst:
voor Python is een hoofdletter een ander teken. Wil je het toestaan, zet dan
bovenaan de functie:
stemming = stemming.lower()
Dan wordt Blij eerst blij, en komt hij door de controle. In de database
staat dan blij, zoals in je lijst.
Zo ziet je main.py er nu uit
import time
from fastapi import FastAPI, Form, HTTPException
from fastapi.staticfiles import StaticFiles
from sqlitedict import SqliteDict
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
STEMMINGEN = ["blij", "neutraal", "boos"]
@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(..., max_length=30),
bericht: str = Form(..., max_length=280),
cijfer: int = Form(..., ge=1, le=10),
stemming: str = Form(...),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
if stemming not in STEMMINGEN:
raise HTTPException(status_code=400, detail="Kies blij, neutraal of boos")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {
"naam": naam,
"bericht": bericht,
"cijfer": cijfer,
"stemming": stemming,
}
db.commit()
return {"lengte": len(bericht), "cijfer": cijfer, "stemming": stemming}
Elk veld heeft nu een controle op de server: de lengte en het getal bewaakt FastAPI, de keuze je eigen lijst.
Door naar les 8: een bestandsnaam van een bezoeker.