URL-Routing und Artikeldetailseiten

In diesem Kapitel lernst du die dynamische Routing-Konfiguration von Django kennen, um Artikeldetailseiten und die Link-Navigation zwischen Seiten zu implementieren.


Was ist dynamisches Routing?

Die Startseite zeigt alle Artikel an, und jeder Artikel benötigt eine eigene unabhängige Detailseite.

Die URL sollte so aussehen:/post/1/、/post/2/, wobei der numerische Teil der Primärschlüssel (pk) des Artikels ist.

Dynamisches RoutingErmöglicht URLs, Variablen zu enthalten, und Django extrahiert sie automatisch und übergibt sie an die View-Funktion.


Dynamisches Routing konfigurieren

Beispiel

# Dateipfad: blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    # int:pk — Integer-Parameter in der URL, benannt pk (Primärschlüssel)
    # name='post_detail' — Route benennen, in Templates mit {% url %} referenziert
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
]

Erklärung des Route-Konverters:

KonverterBeispielpfadÜbereinstimmungsregeln
<int:pk>/post/3/Entspricht positiver Ganzzahl
<str:slug>/post/django-guide/Entspricht einer Zeichenkette (ohne /)
<slug:slug>/post/django-guide/Entspricht Buchstaben, Zahlen, -, _
<uuid:id>/post/uuid/Entspricht UUID-Format

Die Detailseiten-View schreiben

Die Detailseite muss den entsprechenden Artikel anhand der pk in der URL aus der Datenbank abfragen.

Beispiel

# Dateipfad: blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post

def post_detail(request, pk):
    """Artikeldetailseite"""
    # get_object_or_404: einen einzelnen Datensatz abfragen
    # Das Objekt zurückgeben, wenn gefunden; andernfalls automatisch die 404-Seite zurückgeben (ohne try/except zu schreiben)
    post = get_object_or_404(Post, pk=pk)

    context = {
        'post': post,
        'title': f{post.title} - EXAMPLE Blog
    }
    return render(request, 'blog/post_detail.html', context)

get_object_or_404ist Djangos Best Practice. Es entsprichtPost.objects.get(pk=pk) + try/except Post.DoesNotExist, aber der Code ist prägnanter. Wenn Benutzer auf eine nicht existierende Artikel-ID zugreifen, sehen sie eine freundliche 404-Seite statt eines Fehlers.


Detailseiten-Template erstellen

Beispiel

<!-- Dateipfad: blog/templates/blog/post_detail.html -->
{% extends 'blog/base.html' %}

{% block title %}{{ post.title }} - BEISPIEL Blog{% endblock %}

{% block content %}
<article class="post-view">
    <span class="category-tag">{{ post.category.name }}</span>
    <h1>{{ post.title }}</h1>
    <time>{{ post.created_at|date:"Y-m-d" }}</time>

    <!-- Der Body verwendet den |safe-Filter, um HTML zu rendern (HTML-Inhalt, der im Admin eingegeben wurde) -->
    <div class="content">
        {{ post.content|safe }}
    </div>

    <a href="{% url 'index' %}" class="back-link">← Zurück zur Startseite</a>
</article>
{% endblock %}

Detailseiten-Stil

Beispiel

/* An den Stil in base.html anhängen */
.post-view {
    max-width: 720px;
    margin: 0 auto;
}

.category-tag {
    display: inline-block;
    padding: 4px 12px;
    background: #E8EEF5;
    color: #3D71A6;
    border-radius: 12px;
    font-size: 13px;
    margin-bottom: 12px;
}

.post-view h1 {
    font-size: 32px;
    margin-bottom: 12px;
    line-height: 1.4;
}

.post-view time {
    display: block;
    color: #999;
    font-size: 14px;
    margin-bottom: 30px;
}

.content {
    line-height: 1.8;
    font-size: 16px;
    color: #333;
}

.content h2 {
    margin: 24px 0 12px;
    font-size: 22px;
}

.content p {
    margin-bottom: 12px;
}

.back-link {
    display: inline-block;
    margin-top: 40px;
    color: #2c3e50;
    text-decoration: none;
}

|safeDer Filter teilt Django mit: Dieser Inhalt ist sicheres HTML, rendere ihn direkt, escape ihn nicht. Wenn du safe verwendest, stelle sicher, dass der Inhalt vertrauenswürdig ist (z. B. Inhalte, die du selbst im Admin bearbeitet hast). Wenn es sich um von Benutzern eingereichten Inhalt handelt, füge niemals safe hinzu, sonst besteht ein XSS-Risiko.


Links in Templates generieren: {% url %}

Füge den Artikelkarten auf der Startseite Links zur Detailseite hinzu.

Beispiel

<!-- Ändere die Artikelkarte in blog/templates/blog/index.html -->
<div class="article-grid">
    {% for post in posts %}
    <a href="{% url 'post_detail' post.pk %}" class="card-link">
        <div class="article-card">
            <div class="card-content">
                <span class="card-category">{{ post.category.name }}</span>
                <h3>{{ post.title }}</h3>
                <p>{{ post.summary|truncatechars:80 }}</p>
                <span class="card-date">{{ post.created_at|date:"Y-m-d" }}</span>
            </div>
        </div>
    </a>
    {% endfor %}
</div>

{% url 'post_detail' post.pk %}Es generiert automatisch die korrekte URL basierend auf dem Routennamen und den Parametern.

Wenn sich die Route später ändert (z. B.,/post/Wechsel zu/article/), werden die Links im Template automatisch aktualisiert, ohne manuelle Änderung.


Füge get_absolute_url() zum Modell hinzu

Das Definieren dieser Methode im Post-Modell ermöglicht es dem Admin-Backend, den in Django integrierten Tools usw., den Link zur Detailseite automatisch zu finden.

Beispiel

# Dateipfad: zur Post-Klasse in blog/models.py hinzufügen
from django.urls import reverse

class Post(models.Model):
    # ... Felddefinitionen ...
    def __str__(self):
        return self.title

    def get_absolute_url(self):
        # reverse: URL anhand von Routennamen und Parametern nachschlagen
        return reverse('post_detail', kwargs={'pk': self.pk})

Kapitelzusammenfassung

In diesem Kapitel hast du den Kern des Django-Routings gemeistert: dynamisches Routing.<int:pk>Parameterübergabe, sichere Abfrage mit get_object_or_404, {% url %}-Template-Tag zum Generieren von Links, Reverse-URL-Lookup.

Jetzt hat der Blog zwei Seiten: die Startseitenliste und die Artikeldetailseite. Ein Klick auf eine Karte navigiert zum Lesen des vollständigen Artikels.

Weitere Erweiterungen