Invoer controleren: een gastenboek met een formulier
Maak voor deze reeks een nieuwe map veiligheid-invoer, naast je eigen
project, en open die in VS Code. De server, de scripts en de database van deze reeks komen daarin. Zo blijft je eigen gastenboek heel. Aan
het eind van de reeks pas je het geleerde toe op je eigen project.
Maak in die map een virtual environment en installeer de packages; hoe dat gaat staat bij Een map per reeks.
Je zet de server van deze reeks klaar: een gastenboek met een formulier, en een script dat laat zien wat er in de database staat.
Een gastenboek met een formulier
Maak in de map veiligheid-invoer een map static, en zet daarin
formulier.html. Het formulier zet een grens op beide velden, en een grijze
tekst in elk vak, de placeholder, zegt welk vak welk is:
<!doctype html>
<html>
<body>
<form method="post" action="/bericht">
<input type="text" name="naam" placeholder="naam" maxlength="30" required>
<input type="text" name="bericht" placeholder="bericht" maxlength="280" required>
<button type="submit">Verstuur</button>
</form>
</body>
</html>
Zet dit main.py in de map veiligheid-invoer, naast static. De server
slaat op wat binnenkomt, en geeft terug hoe lang het bericht was:
import time
from fastapi import FastAPI, Form
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(...), bericht: str = Form(...)):
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}
- Regel 8:
De map
staticmet het formulier, zoals in CSS in een eigen bestand (static files). - Regel 15:
De lengte van het bericht, zodat je straks ziet wat er binnenkwam.
Een bericht versturen
Stuur de verzoeken in deze reeks uitsluitend naar je eigen server op
127.0.0.1. Een server van een ander volstoppen met grote of veel verzoeken is
een aanval, en strafbaar.
Start je server met fastapi dev main.py en open
http://127.0.0.1:8000/static/formulier.html. Typ je naam in het vak naam
en hoi in het vak bericht, en klik op Verstuur.
Kijk in je database
Wat er in je database staat, zie je met een scriptje naast main.py,
lees_database.py. Het print van elk bericht de naam en hoeveel tekens het
bericht heeft. Het bericht zelf print het niet: in de volgende stappen zijn
berichten soms zo lang dat ze je terminal vullen.
from sqlitedict import SqliteDict
with SqliteDict("gastenboek.db") as db:
for gegevens in db.values():
print(f"[{gegevens['naam']}] {len(gegevens['bericht'])} tekens")
- Regel 4:
db.values()geeft alle berichten, zoals in Alles tonen: een for-lus in je template. - Regel 5:
De naam staat tussen blokhaken, zodat je ook ziet of er spaties in staan. Dat komt in les 5 van pas.
Draai het in de tweede terminal met python lees_database.py.
Er gaat iets mis
Directory 'static' does not exist
De server start niet, en onderaan staat:
RuntimeError: Directory 'static' does not exist
Oorzaak: naast main.py staat geen map static. Je maakte hem ergens
anders, hij heet anders, of je startte de server in een andere map.
Oplossing: maak de map static in veiligheid-invoer, naast main.py,
zet formulier.html erin, en start de server in die map.
lees_database.py print niets
lees_database.py print niets, terwijl de browser wel {"lengte":3} liet zien.
Oorzaak: het script draait in een andere map dan je server.
SqliteDict("gastenboek.db") zoekt het bestand in de map waarin je het script
start. Bestaat het daar niet, dan maakt hij stil een nieuwe, lege database aan.
Oplossing: zet lees_database.py in dezelfde map als main.py, en draai
het vanuit de terminal in die map.
Opdrachten
Opdracht 1: Predict - Een tweede bericht
Je verstuurt met het formulier nog een bericht, tot morgen, en draait
lees_database.py opnieuw.
Vraag: wat toont je browser, en wat print het script?
Tip
Een spatie is ook een teken.
Antwoord
De browser toont {"lengte":10}, en het script print twee regels:
[Sara] 3 tekens
[Sara] 10 tekens
Met jouw naam in plaats van Sara. Het nieuwe bericht staat onderaan.
Zo ziet je main.py er nu uit
import time
from fastapi import FastAPI, Form
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(...), bericht: str = Form(...)):
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}
Naast main.py staat static/formulier.html. In de lessen hierna verandert
vooral de functie bericht_plaatsen.
Door naar les 2: maxlength is geen controle.