Een lijst tonen
Hier bouw je op verder
- Python De for-loop
- Python If en else
- Webontwikkeling Lijsten in HTML
Je gastenboek slaat berichten op, maar om ze te zien moet je nog naar /berichten en een hoop JSON lezen. In deze les zet je ze op een echte pagina.
De for-lus in een template
Tot nu toe vulde je template één waarde in met {{ naam }}. Met {% for %} herhaalt Jinja2 een stuk HTML voor elk item in een lijst:
<ul>
{% for bericht in berichten %}
<li>{{ bericht.naam }}: {{ bericht.bericht }}</li>
{% endfor %}
</ul>
Dit werkt net als een for-lus in Python. Het verschil: er staat {% endfor %} in plaats van inspringen, want HTML kent geen inspringing die betekenis heeft.
De data meesturen
In je endpoint haal je alle berichten op en stuurt ze mee onder de naam die de template gebruikt:
@app.get("/berichten")
async def berichten(request: Request):
with SqliteDict("gastenboek.db") as db:
alle_berichten = list(db.values())
return templates.TemplateResponse(
request,
"berichten.html",
{"berichten": alle_berichten}
)
- Regel 4:
db.values()geeft alle opgeslagen berichten, zonder hun sleutels. Delist()eromheen is het belangrijkste van deze les:db.values()haalt de rijen pas op als je erdoorheen loopt, en dat gebeurt in de template, als de database allang weer dicht is.list()haalt ze binnen hetwith-blok op. Vergeet je dat, dan krijg jeAttributeError: 'NoneType' object has no attribute 'select'. - Regel 8:
De lijst gaat mee onder de naam
berichten, en dat is precies de naam die de template in{% for bericht in berichten %}gebruikt.
Het lege geval
Een gastenboek zonder berichten toont nu een lege <ul>. Met {% if %} vang je dat op:
{% if berichten %}
<ul>
{% for bericht in berichten %}
<li>{{ bericht.naam }}: {{ bericht.bericht }}</li>
{% endfor %}
</ul>
{% else %}
<p>Nog geen berichten. Wees de eerste.</p>
{% endif %}
Compleet voorbeeld
templates/berichten.html:
<!DOCTYPE html>
<html>
<head>
<title>Gastenboek</title>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<h1>Gastenboek</h1>
{% if berichten %}
<ul>
{% for bericht in berichten %}
<li>{{ bericht.naam }}: {{ bericht.bericht }}</li>
{% endfor %}
</ul>
{% else %}
<p>Nog geen berichten. Wees de eerste.</p>
{% endif %}
<a href="/gastenboek">Nieuw bericht</a>
</body>
</html>
Testen
- Start je server en ga naar
http://127.0.0.1:8000/berichten - Zonder berichten zie je "Nog geen berichten"
- Vul het formulier op
/gastenboekeen paar keer in - Ga terug naar
/berichten— je ziet nu een lijst
Blijft de lijst leeg terwijl er wel data in je database staat? Dan komt de lijst waarschijnlijk onder een andere naam binnen dan de template verwacht. Bekijk de troubleshooting pagina voor meer oplossingen.
Opdrachten
Opdracht 1: Predict - Hoeveel regels?
namen = ["Jan", "Sarah", "Piet"]
return templates.TemplateResponse(request, "namen.html", {"namen": namen})
Template:
<h1>Bezoekers</h1>
{% for naam in namen %}
<p>{{ naam }}</p>
{% endfor %}
Vraag: hoeveel <h1> en hoeveel <p> staan er straks op de pagina?
Tip
Alleen wat tússen {% for %} en {% endfor %} staat wordt herhaald. De rest staat er één keer.
Antwoord
Eén <h1> en drie <p>. De <h1> staat buiten de lus, dus die wordt niet herhaald.
Opdracht 2: Run
Maak templates/berichten.html uit het voorbeeld en pas je /berichten endpoint aan. Vul het gastenboek een paar keer in en kijk of je lijst groeit.
Opdracht 3: Investigate - Endfor vergeten
Haal {% endfor %} weg uit je template en herlaad de pagina.
Antwoord
Je krijgt jinja2.exceptions.TemplateSyntaxError: Unexpected end of template. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'.
Jinja2 leest je template van boven naar beneden en wacht op het einde van de lus. Komt dat er niet, dan is het bestand op terwijl de lus nog openstaat. Elke {% for %} heeft een {% endfor %} nodig, en elke {% if %} een {% endif %}.
Opdracht 4: Make - Nummer erbij
Zet een volgnummer voor elk bericht: "1. Jan: Hallo", "2. Sarah: Leuke site".
Tip
Jinja2 houdt zelf bij hoeveel keer de lus gedraaid heeft. Binnen een {% for %} kun je {{ loop.index }} gebruiken; die begint bij 1.
Antwoord
<ul>
{% for bericht in berichten %}
<li>{{ loop.index }}. {{ bericht.naam }}: {{ bericht.bericht }}</li>
{% endfor %}
</ul>
loop.index telt vanaf 1. Wil je vanaf 0 tellen, gebruik dan loop.index0.
Opdracht 5: Make - Tabel met bezoekers
Toon de berichten in een <table> in plaats van een lijst, met twee kolommen: naam en bericht. Zorg dat de kopregel er één keer staat.
Tip
De <tr> met de kopjes hoort buiten de lus. Alleen de <tr> met de data herhaal je.
Antwoord
<table>
<tr>
<th>Naam</th>
<th>Bericht</th>
</tr>
{% for bericht in berichten %}
<tr>
<td>{{ bericht.naam }}</td>
<td>{{ bericht.bericht }}</td>
</tr>
{% endfor %}
</table>
De kopregel staat buiten de lus, dus die verschijnt één keer. De rij met <td> staat erbinnen en wordt per bericht herhaald.