Ga naar hoofdinhoud

Invoer controleren: getallen met een grens

Een gastenboek met een cijfer voor de site, van 1 tot en met 10. In de HTML staat dat netjes:

<input type="number" name="cijfer" placeholder="cijfer" min="1" max="10" required>

Maar min en max zijn net als maxlength uit les 2: de browser houdt je tegen, een script niet. Op de server kan een cijfer dan honderd zijn, of 11, of 0.

Een getal met een grens​

@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),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht, "cijfer": cijfer}
db.commit()
return {"lengte": len(bericht), "cijfer": cijfer}
  1. Regel 5:

    int zegt: dit moet een geheel getal zijn. ge=1 betekent groter dan of gelijk aan 1, le=10 kleiner dan of gelijk aan 10.

  2. Regel 10:

    Het cijfer gaat mee de database in.

Vervang bericht_plaatsen door deze. Zette je in opdracht 2 van les 5 ook een controle op het bericht, neem die twee regels dan mee, onder de controle op de naam. In de code van deze les staan ze niet, net als in de stand van les 5.

Zet het <input> met name="cijfer" in static/formulier.html, binnen het <form>, zodat ook het formulier een cijfer meestuurt.

Doe de test​

Een script cijfer.py probeert vier cijfers:

import httpx

adres = "http://127.0.0.1:8000/bericht"

for cijfer in ["8", "honderd", "11", "0"]:
antwoord = httpx.post(adres, data={"naam": "Sara", "bericht": "hoi", "cijfer": cijfer})
if antwoord.status_code == 200:
print(cijfer, "->", antwoord.json())
else:
print(cijfer, "->", antwoord.status_code, antwoord.json()["detail"][0]["msg"])

Een formulier stuurt alles als tekst, ook "8". FastAPI maakt er een getal van, en weigert wat geen getal is of buiten de grens valt. In je functie is cijfer dus altijd een getal van 1 tot en met 10.

Controlevraag
Een formulier stuurt elk veld als tekst, ook het cijfer 8. Wat is cijfer in je functie?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Er gaat iets mis​

Elk verzoek geeft 422 met cijfer en Field required, ook vanuit het formulier.

Oorzaak: het veld komt niet mee. In het formulier heet het veld anders dan de parameter, of het <input> staat buiten het <form>. Een script uit een eerdere les, zoals fouten.py, stuurt het helemaal niet mee.

Oplossing: controleer dat er name="cijfer" staat, binnen het <form>. Zet in een script "cijfer": "8" bij de data.

Opdrachten​

Opdracht 1: Predict - Een half cijfer​

Je stuurt als cijfer 7.5.

Vraag: wat antwoordt de server?

Antwoord

422, met Input should be a valid integer, unable to parse string as an integer. Een int is een geheel getal; 7.5 is dat niet.

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")

@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),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht, "cijfer": cijfer}
db.commit()
return {"lengte": len(bericht), "cijfer": cijfer}

De lengte en het cijfer bewaakt FastAPI, de naam jij.

Door naar les 7: een keuze uit een lijst.