Erstellen Sie ein eigenes Forum mit FastAPI: Schritt 3 – HTML-Vorlage
James Reed
Infrastructure Engineer · Leapcell

Im vorherigen Artikel haben wir eine PostgreSQL-Datenbank in unser Forum integriert und so eine persistente Datenspeicherung erreicht, sodass die Daten auch bei einem Neustart des Servers nicht mehr verloren gehen.
Jetzt können wir mit Zuversicht weitere Verbesserungen vornehmen. Sie haben jedoch vielleicht bemerkt, dass alle unsere aktuellen Oberflächenstile (HTML) direkt in main.py
geschrieben sind. Bedeutet dies, dass wir für jede neue Funktion in Zukunft mehr HTML in main.py
quetschen müssen?
Das ist nicht nur umständlich zu schreiben, sondern führt auch dazu, dass eine große Menge an HTML-Strings in den Python-Code gemischt wird, was den Code schwer lesbar und wartbar macht.
Um dieses Problem zu lösen, wird in diesem Artikel die Jinja2-Template-Engine vorgestellt, um die Backend-Logik (Python) von der Frontend-Präsentation (HTML) zu trennen und so die Projektstruktur übersichtlicher und leichter wartbar zu gestalten.
Schritt 1: Jinja2 installieren
Die von FastAPI offiziell empfohlene Template-Engine ist Jinja2. Stellen Sie sicher, dass Ihre virtuelle Umgebung aktiviert ist, und führen Sie dann den folgenden Befehl aus:
pip install jinja2
Schritt 2: Verzeichnis und Dateien für Templates erstellen
Um das Projekt besser zu organisieren, müssen wir ein Verzeichnis erstellen, das speziell für die Speicherung von HTML-Vorlagendateien dient.
Erstellen Sie im Stammverzeichnis Ihres Projekts einen neuen Ordner namens templates
.
fastapi-forum/
├── templates/ <-- Neues Verzeichnis
│ └── posts.html <-- Neue Vorlagendatei
├── main.py
├── database.py
├── models.py
└── venv/
Als Nächstes werden wir den HTML-Code aus der generate_html_response
-Funktion in main.py
in die neue Datei templates/posts.html
verschieben und ihn mit Jinja2-Syntax modifizieren.
templates/posts.html
<!DOCTYPE html> <html> <head> <title>Mein FastAPI Forum</title> <style> body { font-family: sans-serif; margin: 2em; } input, textarea { width: 100%; padding: 8px; margin-bottom: 10px; box-sizing: border-box; } button { padding: 10px 15px; background-color: #007bff; color: white; border: none; cursor: pointer; } button:hover { background-color: #0056b3; } </style> </head> <body> <h1>Willkommen in meinem Forum</h1> <h2>Neuen Beitrag erstellen</h2> <form action="/api/posts" method="post"> <input type="text" name="title" placeholder="Titel des Beitrags" required /><br /> <textarea name="content" rows="4" placeholder="Inhalt des Beitrags" required></textarea><br /> <button type="submit">Posten</button> </form> <hr /> <h2>Beitragsliste</h2> {% for post in posts %} <div style="border: 1px solid #ccc; padding: 10px; margin-bottom: 10px;"> <h3>{{ post.title }} (ID: {{ post.id }})</h3> <p>{{ post.content }}</p> </div> {% endfor %} </body> </html>
Die wichtigsten Änderungen finden Sie im Abschnitt Beitragsliste
:
- Verwenden Sie
{% for post in posts %}
und{% endfor %}
, um die Python-for-Schleife zu ersetzen. - Verwenden Sie die Syntax mit doppelten geschweiften Klammern wie
{{ post.title }}
, um Variablen dynamisch einzufügen.
Die Variable posts
wird von unserem FastAPI-Backend beim Rendern der Vorlage übergeben.
Schritt 3: Vorlagen in FastAPI konfigurieren und verwenden
Nachdem nun das HTML getrennt ist, müssen wir main.py
ändern, um FastAPI mitzuteilen, wie diese Vorlagendateien gefunden und verwendet werden sollen.
main.py
(Endgültige Version)
from fastapi import FastAPI, Form, Depends, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, desc from typing import List import models from database import get_db app = FastAPI() # 1. Jinja2Templates konfigurieren templates = Jinja2Templates(directory="templates") # --- Routen --- @app.get("/", response_class=RedirectResponse) def read_root(): return RedirectResponse(url="/posts", status_code=303) # Route zum Anzeigen der Seite @app.get("/posts", response_class=HTMLResponse) async def view_posts(request: Request, db: AsyncSession = Depends(get_db)): # Alle Posts aus der Datenbank abfragen result = await db.execute(select(models.Post).order_by(desc(models.Post.id))) posts = result.scalars().all() # 2. Mit der Vorlage rendern return templates.TemplateResponse("posts.html", {"request": request, "posts": posts}) @app.post("/api/posts") async def create_post( title: str = Form(...), content: str = Form(...), db: AsyncSession = Depends(get_db) ): # Neues Post-Objekt erstellen new_post = models.Post(title=title, content=content) # Zur Datenbank-Sitzung hinzufügen db.add(new_post) # Committen und in der Datenbank speichern await db.commit() # Objekt aktualisieren, um die neu generierte ID zu erhalten await db.refresh(new_post) return RedirectResponse(url="/posts", status_code=303)
Welche Kernänderungen haben wir vorgenommen?
Jinja2Templates
ausfastapi.templating
importiert.- Eine Template-Engine-Instanz mit
templates = Jinja2Templates(directory="templates")
erstellt, die angibt, dass sich die Vorlagendateien im Verzeichnistemplates
befinden. - Die vorherige Funktion
generate_html_response
zum Verketten von HTML-Strings gelöscht und anstelle der Rückgabe einerHTMLResponse
nuntemplates.TemplateResponse()
aufgerufen. TemplateResponse
akzeptiert diese Parameter: den Namen der Vorlagendatei ("posts.html"
) und ein Kontext-Dictionary, das alle Daten enthält, die an die Vorlage übergeben werden sollen. Wir haben dasrequest
-Objekt und die aus der Datenbank abgefragteposts
-Liste übergeben.
Schritt 4: Ausführen und überprüfen
Starten Sie Ihren uvicorn-Server neu:
uvicorn main:app --reload
Öffnen Sie Ihren Browser und gehen Sie zu http://127.0.0.1:8000
. Sie werden feststellen, dass die Seite genau gleich aussieht wie zuvor und alle Funktionen normal funktionieren.
Die interne Struktur des Projekts ist jedoch völlig anders. Ihr Python-Code ist nun nur noch für die Daten- und Logikverarbeitung zuständig, während der HTML-Code sich auf die Anzeige der Inhalte konzentriert. Dies macht die Änderung von Seitenstilen oder das Hinzufügen neuer Funktionen in Zukunft erheblich einfacher und effizienter.
Projekt online bereitstellen
Wie im ersten Tutorial können Sie die Ergebnisse dieses Schritts online bereitstellen, damit Ihre Freunde die Änderungen und Fortschritte des Projekts erleben können.
Eine einfache Bereitstellungslösung ist die Verwendung von Leapcell.
Wenn Sie bereits bereitgestellt haben, pushen Sie einfach den Code in Ihr Git-Repository, und Leapcell stellt den neuesten Code automatisch für Sie neu bereit.
Wenn Sie den Bereitstellungsdienst von Leapcell noch nicht genutzt haben, können Sie das Tutorial in diesem Artikel konsultieren.
Zusammenfassung
Herzlichen Glückwunsch! Sie haben die Jinja2-Template-Engine erfolgreich in Ihr FastAPI-Projekt integriert.
Das aktuelle Forum erlaubt es jedem, anonym zu posten, aber das kann man wirklich nicht als Forum bezeichnen. Eine echte Community benötigt nicht nur verschiedene Benutzer, sondern jeder Benutzer muss auch seine eigene Identität haben.
Im nächsten Artikel werden wir ein Benutzersystem zum Forum hinzufügen und Funktionen zur Benutzerregistrierung und zum Anmelden implementieren, damit jeder Benutzer mit seiner eigenen Identität auf das Forum zugreifen kann.