Erstellen Sie einen perfekten Blog mit FastAPI: Filtern nach Tag
Wenhao Wang
Dev Intern · Leapcell

Im vorherigen Artikel haben wir die Funktionalität zum Erstellen und Anzeigen von Tags für unseren Blog hinzugefügt.
Als Nächstes werden wir den verbleibenden Teil der Tag-Funktionalität abschließen: das Filtern von Beiträgen nach Tags.
Wenn ein Benutzer auf einen Tag-Link klickt, leiten wir ihn zu einer neuen Seite weiter, auf der nur die Beiträge unter diesem speziellen Tag angezeigt werden. Dazu müssen wir eine neue Route und eine entsprechende Handlerfunktion im Backend sowie eine entsprechende Ansicht im Frontend erstellen.
Schritt 1: Erweitern Sie die Service-Logik
Zuerst müssen wir zwei neue Methoden zu tags_service.py
hinzufügen: eine, um einen Tag anhand seiner ID zu finden (um seinen Namen abzurufen), und eine weitere, um alle zugehörigen Beiträge nach einer Tag-ID zu finden.
Öffnen Sie die Datei tags_service.py
und fügen Sie den folgenden Inhalt hinzu:
# tags_service.py import uuid from typing import List from sqlmodel import Session, select from models import Tag, Post, PostTagLink # Import Post und PostTagLink def find_or_create_tags(tag_names: List[str], session: Session) -> List[Tag]: """ Finden oder erstellen Sie Tag-Entitäten basierend auf einer Liste von Tag-Namen. """ # ... diese Funktion bleibt unverändert ... tags = [] if not tag_names: return tags statement = select(Tag).where(Tag.name.in_(tag_names)) existing_tags = session.exec(statement).all() tags.extend(existing_tags) existing_tag_names = {tag.name for tag in existing_tags} new_tag_names = [name for name in tag_names if name not in existing_tag_names altınından] for name in new_tag_names: new_tag = Tag(name=name) session.add(new_tag) tags.append(new_tag) session.commit() for tag in tags: if tag.id is None: session.refresh(tag) return tags def get_tag_by_id(tag_id: uuid.UUID, session: Session) -> Tag | None: """Finden Sie einen einzelnen Tag anhand seiner ID""" return session.get(Tag, tag_id) def get_posts_by_tag_id(tag_id: uuid.UUID, session: Session) -> List[Post]: """Finden Sie alle zugehörigen Beiträge anhand einer Tag-ID""" statement = ( select(Post) .join(PostTagLink, Post.id == PostTagLink.post_id) .where(PostTagLink.tag_id == tag_id) .order_by(Post.createdAt.desc()) ) posts = session.exec(statement).all() return posts
Code-Erklärung:
get_tag_by_id
: Eine einfache Hilfsfunktion, um ein Tag-Objekt anhand seines Primärschlüssels abzurufen.get_posts_by_tag_id
: Dies ist die Kernabfrage-Logik. Wir verwenden die Methodenselect
undjoin
von SQLModel, um allePost
-Objekte zu filtern, die über die AssoziationstabellePostTagLink
mit der gegebenentag_id
verbunden sind, und ordnen sie nach der Erstellungszeit in absteigender Reihenfolge an.
Schritt 2: Erstellen Sie die Tag-Route
Lassen Sie uns nun die Route für die Verarbeitung von Anfragen unter /tags/{tag_id}
implementieren.
Erstellen Sie zuerst eine neue Datei namens tags.py
im Ordner routers
.
# routers/tags.py import uuid from fastapi import APIRouter, Request, Depends from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from sqlmodel import Session from database import get_session from auth_dependencies import get_user_from_session import tags_service import tracking_service router = APIRouter() templates = Jinja2Templates(directory="templates") @router.get("/tags/{tag_id}", response_class=HTMLResponse) def get_posts_by_tag( request: Request, tag_id: uuid.UUID, session: Session = Depends(get_session), user: dict | None = Depends(get_user_from_session), ): # 1. Rufen Sie alle Beiträge unter diesem Tag ab posts = tags_service.get_posts_by_tag_id(tag_id, session) # 2. Rufen Sie die Tag-Informationen ab, um den Tag-Namen auf der Seite anzuzeigen tag = tags_service.get_tag_by_id(tag_id, session) # 3. Batch-Abruf von Aufrufzahlen für die Beitragsliste, um die Konsistenz mit der Startseite zu wahren post_ids = [post.id for post in posts] view_counts = tracking_service.get_counts_by_post_ids(post_ids, session) for post in posts: post.view_count = view_counts.get(post.id, 0) tag_name = tag.name if tag else "Unbekannt" return templates.TemplateResponse( "posts-by-tag.html", { "request": request, "posts": posts, "user": user, "filter_name": tag_name, "title": f"Beiträge in {tag_name}", }, )
Vergessen Sie nicht, dieses neue Router-Modul in main.py
einzubinden.
# main.py # ... andere Importe from routers import posts, users, auth, comments, uploads, tags # importieren Sie den Tags-Router # ... # Router einbinden app.include_router(posts.router) app.include_router(users.router) app.include_router(auth.router) app.include_router(comments.router) app.include_router(uploads.router) app.include_router(tags.router) # Mounten Sie den Tag-Router
Schritt 3: Erstellen Sie die Frontend-Ansicht
Der letzte Schritt ist die Erstellung einer Ansichtsdatei posts-by-tag.html
im Ordner templates
. Diese Datei wird verwendet, um die Liste der nach einem Tag gefilterten Beiträge anzuzeigen, und ihr Inhalt wird dem von index.html
sehr ähnlich sein.
Erstellen Sie die Datei templates/posts-by-tag.html
:
{% include "_header.html" %} <div class="filter-header"> <h2>Beiträge im Tag: <strong>{{ filter_name }}</strong></h2> </div> {% if posts %} <div class="post-list"> {% for post in posts %} <article class="post-item"> <h2><a href="/posts/{{ post.id }}">{{ post.title }}</a></h2> <p>{{ post.content[:150] }}...</p> <small>{{ post.createdAt.strftime('%Y-%m-%d') }} | Aufrufe: {{ post.view_count }}</small> </article> {% endfor %} </div> {% else %} <p>Keine Beiträge in diesem Tag gefunden.</p> {% endif %} <a href="/" class="back-link" style="margin-top: 2rem;">← Zurück zur Startseite</a> {% include "_footer.html" %}
Diese Vorlage zeigt dynamisch einen Titel (z. B. „Beiträge im Tag: Python“) und die Liste der Beiträge unter diesem Tag an. Wenn es keine Beiträge unter dem Tag gibt, wird eine entsprechende Meldung angezeigt.
Ausführen und Testen
Starten Sie Ihre Anwendung neu:
uvicorn main:app --reload
Öffnen Sie Ihren Browser, navigieren Sie zu einem Beitrag, der Tags enthält, und klicken Sie dann auf einen der Tag-Links unter dem Beitrag.
Sie werden auf die Filterseite des entsprechenden Tags weitergeleitet und sehen eine Liste aller Beiträge dieses Tags.
Mit diesen beiden Tutorials haben wir unserem Blog ein vollständiges Tagging-System hinzugefügt.
Zu diesem Zeitpunkt hat unser FastAPI-Blogprojekt alles abgedeckt, von der grundlegenden Infrastruktur über Kernfunktionen bis hin zur Organisation von Inhalten und Datenanalyse.
Das Potenzial für Blog-Funktionen ist grenzenlos. Basierend auf dem aktuellen Framework können Sie weitere Funktionalitäten hinzufügen. Der Rest liegt Ihrer Fantasie überlassen!
Vergessen Sie nicht, auf Leapcell zu deployen – es bietet FastAPI-Unterstützung, eine PostgreSQL-Datenbank, Redis, Web-Analysen und alle Tools, die Sie zum Erstellen von Webanwendungen benötigen.