Einen perfekten Blog mit FastAPI erstellen: Kommentarsystem
Grace Collins
Solutions Engineer · Leapcell

Im vorherigen Artikel haben wir die vollständige Benutzeranmeldung und Sitzungsverwaltung für unseren FastAPI-Blog implementiert. Nun kann der Server den Anmeldestatus eines Benutzers "erkennen" und Seiten schützen, die eine Authentifizierung erfordern.
Da wir nun zwischen eingeloggten Benutzern und Gästen unterscheiden können, ist dies der perfekte Zeitpunkt, um interaktive Funktionen zu unserem Blog hinzuzufügen.
In diesem Artikel fügen wir unserem Blog eine grundlegende, aber entscheidende Funktion hinzu: ein Kommentarsystem.
Konkret werden wir die folgenden Funktionalitäten implementieren:
- Anzeige einer Liste von Kommentaren unter jedem Beitrag.
- Ermöglichen, dass sich eingeloggte Benutzer Kommentare zu Artikeln posten können.
Schritt 1: Erstellen des Datenmodells für Kommentare
Genau wie unsere Modelle Post
und User
benötigt unser Comment
-Modell ein eigenes Datenmodell und Beziehungen zu Post
und User
.
1. Erstellen des Comment-Modells
Öffnen Sie die Datei models.py
, fügen Sie das Comment
-Modell hinzu und aktualisieren Sie die User
- und Post
-Modelle, um eine bidirektionale Beziehung herzustellen.
# models.py import uuid from datetime import datetime from typing import Optional, List from sqlmodel import Field, SQLModel, Relationship class User(SQLModel, table=True): id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True) username: str = Field(unique=True, index=True) password: str # Füge eine Eins-zu-Viele-Beziehung zu Comment hinzu comments: List["Comment"] = Relationship(back_populates="user") class Post(SQLModel, table=True): id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True) title: str content: str createdAt: datetime = Field(default_factory=datetime.utcnow, nullable=False) # Füge eine Eins-zu-Viele-Beziehung zu Comment hinzu comments: List["Comment"] = Relationship(back_populates="post") class Comment(SQLModel, table=True): id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True) content: str createdAt: datetime = Field(default_factory=datetime.utcnow, nullable=False) # Definiere Fremdschlüssel, die auf die Tabellen post und user verweisen postId: uuid.UUID = Field(foreign_key="post.id") userId: uuid.UUID = Field(foreign_key="user.id") # Definiere Viele-zu-Eins-Beziehungen post: Post = Relationship(back_populates="comments") user: User = Relationship(back_populates="comments")
Hier haben wir drei Dinge getan:
- Das
Comment
-Modell erstellt, dascontent
,createdAt
und die FremdschlüsselpostId
unduserId
enthält, die auf die Tabellenpost
unduser
verweisen. Relationship
imComment
-Modell verwendet, um seine "Viele-zu-Eins"-Beziehung zuPost
undUser
zu definieren.- Die umgekehrte "Eins-zu-Viele"-Beziehung
comments
zu denUser
- undPost
-Modellen hinzugefügt. Dies ermöglicht es uns, alle Kommentare zu einemPost
-Objekt oder alle von einemUser
-Objekt erstellten Kommentare einfach abzurufen.
Da wir die Funktion create_db_and_tables
in main.py
konfiguriert haben, wird sie die SQLModel
-Modelle automatisch erkennen und die entsprechenden Datenbanktabellen beim Start der Anwendung erstellen oder aktualisieren. Wir müssen keine SQL manuell ausführen.
Wenn Sie SQL manuell ausführen müssen und Ihre Datenbank auf Leapcell erstellt wurde,
können Sie SQL-Anweisungen ganz einfach über die grafische Oberfläche ausführen. Gehen Sie einfach auf die Seite zur Datenbankverwaltung auf der Website, fügen Sie die obigen Anweisungen in die SQL-Oberfläche ein und führen Sie sie aus.
Schritt 2: Implementieren der Geschäftslogik für Kommentare
Als Nächstes erstellen wir Funktionen zur Verarbeitung von Kommentarerstellung und -abfragen.
Erstellen Sie eine neue Datei comments_service.py
im Stammverzeichnis des Projekts, um die Geschäftslogik im Zusammenhang mit Kommentaren zu speichern.
# comments_service.py import uuid from typing import List from sqlmodel import Session, select from models import Comment def get_comments_by_post_id(post_id: uuid.UUID, session: Session) -> List[Comment]: """Findet alle Kommentare für eine gegebene Post-ID und sortiert sie aufsteigend nach Erstellungszeit.""" statement = select(Comment).where(Comment.postId == post_id).order_by(Comment.createdAt) comments = session.exec(statement).all() return comments def create_comment(content: str, user_id: uuid.UUID, post_id: uuid.UUID, session: Session) -> Comment: """Erstellt einen neuen Kommentar.""" new_comment = Comment(content=content, userId=user_id, postId=post_id) session.add(new_comment) session.commit() session.refresh(new_comment) return new_comment
Die Funktion get_comments_by_post_id
wird verwendet, um alle Kommentare unter einem Beitrag abzurufen. create_comment
wird verwendet, um einen neuen Kommentar in der Datenbank zu speichern. Da wir die Relationship
in unseren Modellen korrekt eingerichtet haben, können wir später bequem den Benutzernamen des Kommentators in der Vorlage über comment.user.username
abrufen.
Schritt 3: Erstellen von Routen für das Einreichen und Anzeigen von Kommentaren
Jetzt müssen wir die Kommentarfunktionalität in die Beitragsseite integrieren. Dies erfordert zwei Teile: eine Backend-Route, die vom Benutzer eingereichte Kommentare empfängt, und eine Aktualisierung der Route für die Beitragsdetailseite, um die Kommentare anzuzeigen.
1. Erstellen der Kommentar-Route
Erstellen Sie eine neue Datei comments.py
im Ordner routers
:
# routers/comments.py import uuid from fastapi import APIRouter, Depends, Form from fastapi.responses import RedirectResponse from sqlmodel import Session from database import get_session import comments_service from auth_dependencies import login_required router = APIRouter() @router.post("/posts/{post_id}/comments") def create_comment_for_post( post_id: uuid.UUID, content: str = Form(...), user: dict = Depends(login_required), # Dependency Injection zur Sicherstellung, dass der Benutzer eingeloggt ist session: Session = Depends(get_session) ): # Die Benutzer-ID aus der Sitzung ist eine Zeichenkette und muss in den Typ UUID konvertiert werden user_id = uuid.UUID(user["id"]) comments_service.create_comment( content=content, user_id=user_id, post_id=post_id, session=session ) # Nach einem erfolgreichen Kommentar zurück zur Beitragsseite umleiten return RedirectResponse(url=f"/posts/{post_id}", status_code=302)
Diese Route verarbeitet nur POST
-Anfragen. Wir verwenden die zuvor erstellte login_required
-Abhängigkeit, um sie zu schützen und sicherzustellen, dass nur eingeloggte Benutzer Kommentare posten können. Nachdem ein Kommentar erfolgreich erstellt wurde, wird die Seite zur ursprünglichen Beitragsdetailseite umgeleitet.
2. Aktualisieren der Hauptanwendung und der Beitragsrouten
Zuerst binden wir den gerade erstellten Kommentar-Router in main.py
ein.
# main.py # ... weitere Importe from routers import posts, users, auth, comments # importiere den comments-router # ... app = FastAPI(lifespan=lifespan) # ... # Router einbinden app.include_router(posts.router) app.include_router(users.router) app.include_router(auth.router) app.include_router(comments.router) # Binde den comments-router ein
Als Nächstes ändern wir die Funktion get_post_by_id
in routers/posts.py
, sodass beim Rendern der Beitragsdetailseite auch alle Kommentare für diesen Beitrag abgerufen und übergeben werden.
# routers/posts.py # ... Importe ... from auth_dependencies import get_user_from_session import comments_service # Importiere den comment service # ... Router und Templates Definition ... # ... weitere Routen ... @router.get("/posts/{post_id}", response_class=HTMLResponse) def get_post_by_id( request: Request, post_id: uuid.UUID, session: Session = Depends(get_session), user: dict | None = Depends(get_user_from_session) ): post = session.get(Post, post_id) # Rufe alle Kommentare für diesen Beitrag ab comments = comments_service.get_comments_by_post_id(post_id, session) # Übergib post, user und comments zusammen an das Template return templates.TemplateResponse( "post.html", { "request": request, "post": post, "title": post.title, "user": user, "comments": comments # Neu } )
Schritt 4: Aktualisieren der Frontend-Ansicht
Der letzte Schritt ist die Änderung der Vorlagendatei, um die Kommentarliste und das Kommentarformular anzuzeigen.
Öffnen Sie templates/post.html
und fügen Sie den folgenden Code unter dem Beitragstext und über dem Link zurück hinzu:
<div class="post-content">{{ post.content | replace('\n', '<br>') | safe }}</div> </article> <section class="comments-section"> <h3>Kommentare</h3> <div class="comment-list"> {% if comments %} {% for comment in comments %} <div class="comment-item"> <p class="comment-content">{{ comment.content }}</p> <small> Von <strong>{{ comment.user.username }}</strong> am {{ comment.createdAt.strftime('%Y-%m-%d') }} </small> </div> {% endfor %} {% else %} <p>Noch keine Kommentare. Sei der/die Erste!</p> {% endif %} </div> {% if user %} <form action="/posts/{{ post.id }}/comments" method="POST" class="comment-form"> <h4>Hinterlasse einen Kommentar</h4> <div class="form-group"> <textarea name="content" rows="4" placeholder="Schreib deinen Kommentar hier..." required></textarea> </div> <button type="submit">Kommentar absenden</button> </form> {% else %} <p><a href="/auth/login">Anmelden</a>, um einen Kommentar zu hinterlassen.</p> {% endif %} </section> <a href="/" class="back-link">← Zurück zur Startseite</a> {% include "_footer.html" %}
- Wir verwenden
{% for comment in comments %}
, um durch alle Kommentare zu schleifen und sie anzuzeigen. Übercomment.user.username
können wir direkt den Benutzernamen des Kommentierenden anzeigen. - Wir verwenden
{% if user %}
, um zu prüfen, ob der Benutzer eingeloggt ist. Wenn ja, wird das Kommentarformular angezeigt, andernfalls wird ein Anmelde-Link angezeigt.
Damit die Seite besser aussieht, können Sie einige Stile zu public/css/style.css
hinzufügen:
/* ... andere Stile ... */ .comments-section { margin-top: 3rem; border-top: 1px solid #eee; padding-top: 2rem; } .comment-list .comment-item { background: #f9f9f9; border: 1px solid #ddd; padding: 1rem; border-radius: 5px; margin-bottom: 1rem; } .comment-content { margin-top: 0; } .comment-item small { color: #666; } .comment-form { margin-top: 2rem; } .comment-form textarea { width: 100%; padding: 0.5rem; margin-bottom: 1rem; border: 1px solid #ccc; border-radius: 4px; }
Ausführen und Testen
Starten Sie nun Ihre Anwendung neu:
```} "slug": "einen-perfekten-blog-mit-fastapi-erstellen-kommentarsystem" }f```json uvicorn main:app --reload
Öffnen Sie Ihren Browser und navigieren Sie zur Detailseite eines beliebigen Beitrags. Sie sehen den neuen Kommentarbereich.
Geben Sie etwas in das Kommentarfeld ein und senden Sie es ab. Nach der Aktualisierung der Seite sehen Sie den gerade gesendeten Kommentar in der Kommentarliste.
Herzlichen Glückwunsch, Sie haben erfolgreich ein Kommentarsystem zu Ihrem Blog hinzugefügt!
Natürlich ist die aktuelle Kommentarfunktionalität noch recht einfach. Im nächsten Artikel werden wir diese Funktion weiter verbessern, indem wir die Logik für Antworten von Autoren auf Kommentare implementieren und so die Interaktivität des Blogs auf die nächste Stufe heben.