Ga naar hoofdinhoud

Invoer controleren: een gastenboek met een formulier

Waar je werkt

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)}
  1. Regel 8:

    De map static met het formulier, zoals in CSS in een eigen bestand (static files).

  2. Regel 15:

    De lengte van het bericht, zodat je straks ziet wat er binnenkwam.

Een bericht versturen​

Alleen je eigen server

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")
  1. Regel 4:

    db.values() geeft alle berichten, zoals in Alles tonen: een for-lus in je template.

  2. 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.

Controlevraag
Je opent http://127.0.0.1:8000/formulier.html, zonder /static ervoor. Wat krijg je?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

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.